1651f58bfSDiana Picus //===-- runtime/unit-map.cpp ----------------------------------------------===//
23b635714Speter klausler //
33b635714Speter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43b635714Speter klausler // See https://llvm.org/LICENSE.txt for license information.
53b635714Speter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63b635714Speter klausler //
73b635714Speter klausler //===----------------------------------------------------------------------===//
83b635714Speter klausler
93b635714Speter klausler #include "unit-map.h"
10*71e0261fSSlava Zakharin #include "flang/Common/optional.h"
113b635714Speter klausler
123b635714Speter klausler namespace Fortran::runtime::io {
133b635714Speter klausler
Initialize()1473b193aeSPeter Klausler void UnitMap::Initialize() {
1573b193aeSPeter Klausler if (!isInitialized_) {
1673b193aeSPeter Klausler freeNewUnits_.InitializeState();
1773b193aeSPeter Klausler // Unit number -1 is reserved.
1873b193aeSPeter Klausler // The unit numbers are pushed in reverse order so that the first
1973b193aeSPeter Klausler // ones to be popped will be small and suitable for use as kind=1
2073b193aeSPeter Klausler // integers.
2173b193aeSPeter Klausler for (int j{freeNewUnits_.maxValue}; j > 1; --j) {
2273b193aeSPeter Klausler freeNewUnits_.Add(j);
2373b193aeSPeter Klausler }
2473b193aeSPeter Klausler isInitialized_ = true;
2573b193aeSPeter Klausler }
2673b193aeSPeter Klausler }
2773b193aeSPeter Klausler
28c7f4c333SPeter Klausler // See 12.5.6.12 in Fortran 2018. NEWUNIT= unit numbers are negative,
2973b193aeSPeter Klausler // and not equal to -1 (or ERROR_UNIT, if it were negative, which it isn't.)
NewUnit(const Terminator & terminator)30c7f4c333SPeter Klausler ExternalFileUnit &UnitMap::NewUnit(const Terminator &terminator) {
31c7f4c333SPeter Klausler CriticalSection critical{lock_};
3273b193aeSPeter Klausler Initialize();
33*71e0261fSSlava Zakharin Fortran::common::optional<int> n{freeNewUnits_.PopValue()};
3473b193aeSPeter Klausler if (!n) {
3573b193aeSPeter Klausler n = emergencyNewUnit_++;
36c7f4c333SPeter Klausler }
3773b193aeSPeter Klausler return Create(-*n, terminator);
38c7f4c333SPeter Klausler }
39c7f4c333SPeter Klausler
LookUpForClose(int n)403b635714Speter klausler ExternalFileUnit *UnitMap::LookUpForClose(int n) {
413b635714Speter klausler CriticalSection critical{lock_};
423b635714Speter klausler Chain *previous{nullptr};
433b635714Speter klausler int hash{Hash(n)};
443b635714Speter klausler for (Chain *p{bucket_[hash].get()}; p; previous = p, p = p->next.get()) {
453b635714Speter klausler if (p->unit.unitNumber() == n) {
463b635714Speter klausler if (previous) {
473b635714Speter klausler previous->next.swap(p->next);
483b635714Speter klausler } else {
493b635714Speter klausler bucket_[hash].swap(p->next);
503b635714Speter klausler }
513b635714Speter klausler // p->next.get() == p at this point; the next swap pushes p on closing_
523b635714Speter klausler closing_.swap(p->next);
533b635714Speter klausler return &p->unit;
543b635714Speter klausler }
553b635714Speter klausler }
563b635714Speter klausler return nullptr;
573b635714Speter klausler }
583b635714Speter klausler
DestroyClosed(ExternalFileUnit & unit)593b635714Speter klausler void UnitMap::DestroyClosed(ExternalFileUnit &unit) {
603b635714Speter klausler Chain *p{nullptr};
613b635714Speter klausler {
623b635714Speter klausler CriticalSection critical{lock_};
633b635714Speter klausler Chain *previous{nullptr};
643b635714Speter klausler for (p = closing_.get(); p; previous = p, p = p->next.get()) {
653b635714Speter klausler if (&p->unit == &unit) {
66c7f4c333SPeter Klausler int n{unit.unitNumber()};
67c7f4c333SPeter Klausler if (n <= -2) {
6873b193aeSPeter Klausler freeNewUnits_.Add(-n);
69c7f4c333SPeter Klausler }
703b635714Speter klausler if (previous) {
713b635714Speter klausler previous->next.swap(p->next);
723b635714Speter klausler } else {
733b635714Speter klausler closing_.swap(p->next);
743b635714Speter klausler }
753b635714Speter klausler break;
763b635714Speter klausler }
773b635714Speter klausler }
783b635714Speter klausler }
793b635714Speter klausler if (p) {
803b635714Speter klausler p->unit.~ExternalFileUnit();
813b635714Speter klausler FreeMemory(p);
823b635714Speter klausler }
833b635714Speter klausler }
843b635714Speter klausler
CloseAll(IoErrorHandler & handler)853b635714Speter klausler void UnitMap::CloseAll(IoErrorHandler &handler) {
86c84616c3SPeter Klausler // Extract units from the map so they can be closed
87c84616c3SPeter Klausler // without holding lock_.
88c84616c3SPeter Klausler OwningPtr<Chain> closeList;
89c84616c3SPeter Klausler {
903b635714Speter klausler CriticalSection critical{lock_};
913b635714Speter klausler for (int j{0}; j < buckets_; ++j) {
923b635714Speter klausler while (Chain * p{bucket_[j].get()}) {
93c84616c3SPeter Klausler bucket_[j].swap(p->next); // pops p from head of bucket list
94c84616c3SPeter Klausler closeList.swap(p->next); // pushes p to closeList
95c84616c3SPeter Klausler }
96c84616c3SPeter Klausler }
97c84616c3SPeter Klausler }
98c84616c3SPeter Klausler while (Chain * p{closeList.get()}) {
99c84616c3SPeter Klausler closeList.swap(p->next); // pops p from head of closeList
1003b635714Speter klausler p->unit.CloseUnit(CloseStatus::Keep, handler);
1013b635714Speter klausler p->unit.~ExternalFileUnit();
1023b635714Speter klausler FreeMemory(p);
1033b635714Speter klausler }
1043b635714Speter klausler }
1053b635714Speter klausler
FlushAll(IoErrorHandler & handler)1060006354cSpeter klausler void UnitMap::FlushAll(IoErrorHandler &handler) {
1070006354cSpeter klausler CriticalSection critical{lock_};
1080006354cSpeter klausler for (int j{0}; j < buckets_; ++j) {
1090006354cSpeter klausler for (Chain *p{bucket_[j].get()}; p; p = p->next.get()) {
110cd0a1226Speter klausler p->unit.FlushOutput(handler);
1110006354cSpeter klausler }
1120006354cSpeter klausler }
1130006354cSpeter klausler }
1140006354cSpeter klausler
Find(const char * path,std::size_t pathLen)11503c066abSPeter Klausler ExternalFileUnit *UnitMap::Find(const char *path, std::size_t pathLen) {
116675ad1bcSpeter klausler if (path) {
117675ad1bcSpeter klausler // TODO: Faster data structure
118675ad1bcSpeter klausler for (int j{0}; j < buckets_; ++j) {
119675ad1bcSpeter klausler for (Chain *p{bucket_[j].get()}; p; p = p->next.get()) {
12003c066abSPeter Klausler if (p->unit.path() && p->unit.pathLength() == pathLen &&
12103c066abSPeter Klausler std::memcmp(p->unit.path(), path, pathLen) == 0) {
122675ad1bcSpeter klausler return &p->unit;
123675ad1bcSpeter klausler }
124675ad1bcSpeter klausler }
125675ad1bcSpeter klausler }
126675ad1bcSpeter klausler }
127675ad1bcSpeter klausler return nullptr;
128675ad1bcSpeter klausler }
129675ad1bcSpeter klausler
Create(int n,const Terminator & terminator)1303b635714Speter klausler ExternalFileUnit &UnitMap::Create(int n, const Terminator &terminator) {
13198d576c7Speter klausler Chain &chain{*New<Chain>{terminator}(n).release()};
1323b635714Speter klausler chain.next.reset(&chain);
1333b635714Speter klausler bucket_[Hash(n)].swap(chain.next); // pushes new node as list head
1343b635714Speter klausler return chain.unit;
1353b635714Speter klausler }
13643fadefbSpeter klausler
1371f879005STim Keith } // namespace Fortran::runtime::io
138