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"
103b635714Speter klausler
113b635714Speter klausler namespace Fortran::runtime::io {
123b635714Speter klausler
Initialize()1373b193aeSPeter Klausler void UnitMap::Initialize() {
1473b193aeSPeter Klausler if (!isInitialized_) {
1573b193aeSPeter Klausler freeNewUnits_.InitializeState();
1673b193aeSPeter Klausler // Unit number -1 is reserved.
1773b193aeSPeter Klausler // The unit numbers are pushed in reverse order so that the first
1873b193aeSPeter Klausler // ones to be popped will be small and suitable for use as kind=1
1973b193aeSPeter Klausler // integers.
2073b193aeSPeter Klausler for (int j{freeNewUnits_.maxValue}; j > 1; --j) {
2173b193aeSPeter Klausler freeNewUnits_.Add(j);
2273b193aeSPeter Klausler }
2373b193aeSPeter Klausler isInitialized_ = true;
2473b193aeSPeter Klausler }
2573b193aeSPeter Klausler }
2673b193aeSPeter Klausler
27c7f4c333SPeter Klausler // See 12.5.6.12 in Fortran 2018. NEWUNIT= unit numbers are negative,
2873b193aeSPeter Klausler // and not equal to -1 (or ERROR_UNIT, if it were negative, which it isn't.)
NewUnit(const Terminator & terminator)29c7f4c333SPeter Klausler ExternalFileUnit &UnitMap::NewUnit(const Terminator &terminator) {
30c7f4c333SPeter Klausler CriticalSection critical{lock_};
3173b193aeSPeter Klausler Initialize();
3273b193aeSPeter Klausler std::optional<int> n{freeNewUnits_.PopValue()};
3373b193aeSPeter Klausler if (!n) {
3473b193aeSPeter Klausler n = emergencyNewUnit_++;
35c7f4c333SPeter Klausler }
3673b193aeSPeter Klausler return Create(-*n, terminator);
37c7f4c333SPeter Klausler }
38c7f4c333SPeter Klausler
LookUpForClose(int n)393b635714Speter klausler ExternalFileUnit *UnitMap::LookUpForClose(int n) {
403b635714Speter klausler CriticalSection critical{lock_};
413b635714Speter klausler Chain *previous{nullptr};
423b635714Speter klausler int hash{Hash(n)};
433b635714Speter klausler for (Chain *p{bucket_[hash].get()}; p; previous = p, p = p->next.get()) {
443b635714Speter klausler if (p->unit.unitNumber() == n) {
453b635714Speter klausler if (previous) {
463b635714Speter klausler previous->next.swap(p->next);
473b635714Speter klausler } else {
483b635714Speter klausler bucket_[hash].swap(p->next);
493b635714Speter klausler }
503b635714Speter klausler // p->next.get() == p at this point; the next swap pushes p on closing_
513b635714Speter klausler closing_.swap(p->next);
523b635714Speter klausler return &p->unit;
533b635714Speter klausler }
543b635714Speter klausler }
553b635714Speter klausler return nullptr;
563b635714Speter klausler }
573b635714Speter klausler
DestroyClosed(ExternalFileUnit & unit)583b635714Speter klausler void UnitMap::DestroyClosed(ExternalFileUnit &unit) {
593b635714Speter klausler Chain *p{nullptr};
603b635714Speter klausler {
613b635714Speter klausler CriticalSection critical{lock_};
623b635714Speter klausler Chain *previous{nullptr};
633b635714Speter klausler for (p = closing_.get(); p; previous = p, p = p->next.get()) {
643b635714Speter klausler if (&p->unit == &unit) {
65c7f4c333SPeter Klausler int n{unit.unitNumber()};
66c7f4c333SPeter Klausler if (n <= -2) {
6773b193aeSPeter Klausler freeNewUnits_.Add(-n);
68c7f4c333SPeter Klausler }
693b635714Speter klausler if (previous) {
703b635714Speter klausler previous->next.swap(p->next);
713b635714Speter klausler } else {
723b635714Speter klausler closing_.swap(p->next);
733b635714Speter klausler }
743b635714Speter klausler break;
753b635714Speter klausler }
763b635714Speter klausler }
773b635714Speter klausler }
783b635714Speter klausler if (p) {
793b635714Speter klausler p->unit.~ExternalFileUnit();
803b635714Speter klausler FreeMemory(p);
813b635714Speter klausler }
823b635714Speter klausler }
833b635714Speter klausler
CloseAll(IoErrorHandler & handler)843b635714Speter klausler void UnitMap::CloseAll(IoErrorHandler &handler) {
85c84616c3SPeter Klausler // Extract units from the map so they can be closed
86c84616c3SPeter Klausler // without holding lock_.
87c84616c3SPeter Klausler OwningPtr<Chain> closeList;
88c84616c3SPeter Klausler {
893b635714Speter klausler CriticalSection critical{lock_};
903b635714Speter klausler for (int j{0}; j < buckets_; ++j) {
913b635714Speter klausler while (Chain * p{bucket_[j].get()}) {
92c84616c3SPeter Klausler bucket_[j].swap(p->next); // pops p from head of bucket list
93c84616c3SPeter Klausler closeList.swap(p->next); // pushes p to closeList
94c84616c3SPeter Klausler }
95c84616c3SPeter Klausler }
96c84616c3SPeter Klausler }
97c84616c3SPeter Klausler while (Chain * p{closeList.get()}) {
98c84616c3SPeter Klausler closeList.swap(p->next); // pops p from head of closeList
993b635714Speter klausler p->unit.CloseUnit(CloseStatus::Keep, handler);
1003b635714Speter klausler p->unit.~ExternalFileUnit();
1013b635714Speter klausler FreeMemory(p);
1023b635714Speter klausler }
1033b635714Speter klausler }
1043b635714Speter klausler
FlushAll(IoErrorHandler & handler)1050006354cSpeter klausler void UnitMap::FlushAll(IoErrorHandler &handler) {
1060006354cSpeter klausler CriticalSection critical{lock_};
1070006354cSpeter klausler for (int j{0}; j < buckets_; ++j) {
1080006354cSpeter klausler for (Chain *p{bucket_[j].get()}; p; p = p->next.get()) {
109cd0a1226Speter klausler p->unit.FlushOutput(handler);
1100006354cSpeter klausler }
1110006354cSpeter klausler }
1120006354cSpeter klausler }
1130006354cSpeter klausler
Find(const char * path,std::size_t pathLen)114*03c066abSPeter Klausler ExternalFileUnit *UnitMap::Find(const char *path, std::size_t pathLen) {
115675ad1bcSpeter klausler if (path) {
116675ad1bcSpeter klausler // TODO: Faster data structure
117675ad1bcSpeter klausler for (int j{0}; j < buckets_; ++j) {
118675ad1bcSpeter klausler for (Chain *p{bucket_[j].get()}; p; p = p->next.get()) {
119*03c066abSPeter Klausler if (p->unit.path() && p->unit.pathLength() == pathLen &&
120*03c066abSPeter Klausler std::memcmp(p->unit.path(), path, pathLen) == 0) {
121675ad1bcSpeter klausler return &p->unit;
122675ad1bcSpeter klausler }
123675ad1bcSpeter klausler }
124675ad1bcSpeter klausler }
125675ad1bcSpeter klausler }
126675ad1bcSpeter klausler return nullptr;
127675ad1bcSpeter klausler }
128675ad1bcSpeter klausler
Create(int n,const Terminator & terminator)1293b635714Speter klausler ExternalFileUnit &UnitMap::Create(int n, const Terminator &terminator) {
13098d576c7Speter klausler Chain &chain{*New<Chain>{terminator}(n).release()};
1313b635714Speter klausler chain.next.reset(&chain);
1323b635714Speter klausler bucket_[Hash(n)].swap(chain.next); // pushes new node as list head
1333b635714Speter klausler return chain.unit;
1343b635714Speter klausler }
13543fadefbSpeter klausler
1361f879005STim Keith } // namespace Fortran::runtime::io
137