xref: /llvm-project/flang/runtime/unit-map.cpp (revision 71e0261fb0c6c382f68eedddf6bbcf637e6709f2)
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