1 //===-- runtime/unit-map.cpp ----------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "unit-map.h" 10 11 namespace Fortran::runtime::io { 12 13 ExternalFileUnit *UnitMap::LookUpForClose(int n) { 14 CriticalSection critical{lock_}; 15 Chain *previous{nullptr}; 16 int hash{Hash(n)}; 17 for (Chain *p{bucket_[hash].get()}; p; previous = p, p = p->next.get()) { 18 if (p->unit.unitNumber() == n) { 19 if (previous) { 20 previous->next.swap(p->next); 21 } else { 22 bucket_[hash].swap(p->next); 23 } 24 // p->next.get() == p at this point; the next swap pushes p on closing_ 25 closing_.swap(p->next); 26 return &p->unit; 27 } 28 } 29 return nullptr; 30 } 31 32 void UnitMap::DestroyClosed(ExternalFileUnit &unit) { 33 Chain *p{nullptr}; 34 { 35 CriticalSection critical{lock_}; 36 Chain *previous{nullptr}; 37 for (p = closing_.get(); p; previous = p, p = p->next.get()) { 38 if (&p->unit == &unit) { 39 if (previous) { 40 previous->next.swap(p->next); 41 } else { 42 closing_.swap(p->next); 43 } 44 break; 45 } 46 } 47 } 48 if (p) { 49 p->unit.~ExternalFileUnit(); 50 FreeMemory(p); 51 } 52 } 53 54 void UnitMap::CloseAll(IoErrorHandler &handler) { 55 // Extract units from the map so they can be closed 56 // without holding lock_. 57 OwningPtr<Chain> closeList; 58 { 59 CriticalSection critical{lock_}; 60 for (int j{0}; j < buckets_; ++j) { 61 while (Chain * p{bucket_[j].get()}) { 62 bucket_[j].swap(p->next); // pops p from head of bucket list 63 closeList.swap(p->next); // pushes p to closeList 64 } 65 } 66 } 67 while (Chain * p{closeList.get()}) { 68 closeList.swap(p->next); // pops p from head of closeList 69 p->unit.CloseUnit(CloseStatus::Keep, handler); 70 p->unit.~ExternalFileUnit(); 71 FreeMemory(p); 72 } 73 } 74 75 void UnitMap::FlushAll(IoErrorHandler &handler) { 76 CriticalSection critical{lock_}; 77 for (int j{0}; j < buckets_; ++j) { 78 for (Chain *p{bucket_[j].get()}; p; p = p->next.get()) { 79 p->unit.FlushOutput(handler); 80 } 81 } 82 } 83 84 ExternalFileUnit *UnitMap::Find(const char *path) { 85 if (path) { 86 // TODO: Faster data structure 87 for (int j{0}; j < buckets_; ++j) { 88 for (Chain *p{bucket_[j].get()}; p; p = p->next.get()) { 89 if (p->unit.path() && std::strcmp(p->unit.path(), path) == 0) { 90 return &p->unit; 91 } 92 } 93 } 94 } 95 return nullptr; 96 } 97 98 ExternalFileUnit &UnitMap::Create(int n, const Terminator &terminator) { 99 Chain &chain{*New<Chain>{terminator}(n).release()}; 100 chain.next.reset(&chain); 101 bucket_[Hash(n)].swap(chain.next); // pushes new node as list head 102 return chain.unit; 103 } 104 105 } // namespace Fortran::runtime::io 106