forked from OSchip/llvm-project
[flang] Make NEWUNIT= use a range suitable for INTEGER(KIND=1) and recycle unit numbers
Use a bit-set to manage runtime-generated I/O unit numbers, recycle them after they're closed, and use a range of values that fits in a minimal-sized integer. Differential Revision: https://reviews.llvm.org/D118651
This commit is contained in:
parent
9aa2c914b9
commit
c7f4c333af
|
@ -304,7 +304,8 @@ Cookie IONAME(BeginOpenUnit)( // OPEN(without NEWUNIT=)
|
|||
Cookie IONAME(BeginOpenNewUnit)( // OPEN(NEWUNIT=j)
|
||||
const char *sourceFile, int sourceLine) {
|
||||
Terminator terminator{sourceFile, sourceLine};
|
||||
ExternalFileUnit &unit{ExternalFileUnit::NewUnit(terminator)};
|
||||
ExternalFileUnit &unit{
|
||||
ExternalFileUnit::NewUnit(terminator, false /*not child I/O*/)};
|
||||
return &unit.BeginIoStatement<OpenStatementState>(
|
||||
unit, false /*was an existing file*/, sourceFile, sourceLine);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,21 @@
|
|||
|
||||
namespace Fortran::runtime::io {
|
||||
|
||||
// See 12.5.6.12 in Fortran 2018. NEWUNIT= unit numbers are negative,
|
||||
// and not equal -1 (or ERROR_UNIT, if it were negative, which it isn't.)
|
||||
ExternalFileUnit &UnitMap::NewUnit(const Terminator &terminator) {
|
||||
CriticalSection critical{lock_};
|
||||
std::optional<std::size_t> n;
|
||||
n = (~busyNewUnits_).LeastElement();
|
||||
if (!n.has_value()) {
|
||||
terminator.Crash(
|
||||
"No available unit number for NEWUNIT= or internal child I/O");
|
||||
}
|
||||
busyNewUnits_.set(*n);
|
||||
// bit position 0 <-> unit -2; kind=1 units are in [-65..-2]
|
||||
return Create(static_cast<int>(-2 - *n), terminator);
|
||||
}
|
||||
|
||||
ExternalFileUnit *UnitMap::LookUpForClose(int n) {
|
||||
CriticalSection critical{lock_};
|
||||
Chain *previous{nullptr};
|
||||
|
@ -36,6 +51,10 @@ void UnitMap::DestroyClosed(ExternalFileUnit &unit) {
|
|||
Chain *previous{nullptr};
|
||||
for (p = closing_.get(); p; previous = p, p = p->next.get()) {
|
||||
if (&p->unit == &unit) {
|
||||
int n{unit.unitNumber()};
|
||||
if (n <= -2) {
|
||||
busyNewUnits_.reset(static_cast<std::size_t>(-2 - n));
|
||||
}
|
||||
if (previous) {
|
||||
previous->next.swap(p->next);
|
||||
} else {
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
#include "lock.h"
|
||||
#include "unit.h"
|
||||
#include "flang/Common/constexpr-bitset.h"
|
||||
#include "flang/Runtime/memory.h"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace Fortran::runtime::io {
|
||||
|
@ -40,10 +42,7 @@ public:
|
|||
return Find(path);
|
||||
}
|
||||
|
||||
ExternalFileUnit &NewUnit(const Terminator &terminator) {
|
||||
CriticalSection critical{lock_};
|
||||
return Create(nextNewUnit_--, terminator);
|
||||
}
|
||||
ExternalFileUnit &NewUnit(const Terminator &);
|
||||
|
||||
// To prevent races, the unit is removed from the map if it exists,
|
||||
// and put on the closing_ list until DestroyClosed() is called.
|
||||
|
@ -84,7 +83,7 @@ private:
|
|||
|
||||
Lock lock_;
|
||||
OwningPtr<Chain> bucket_[buckets_]{}; // all owned by *this
|
||||
int nextNewUnit_{-1000}; // see 12.5.6.12 in Fortran 2018
|
||||
common::BitSet<64> busyNewUnits_;
|
||||
OwningPtr<Chain> closing_{nullptr}; // units during CLOSE statement
|
||||
};
|
||||
} // namespace Fortran::runtime::io
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
static ExternalFileUnit *LookUp(const char *path);
|
||||
static ExternalFileUnit &CreateNew(int unit, const Terminator &);
|
||||
static ExternalFileUnit *LookUpForClose(int unit);
|
||||
static ExternalFileUnit &NewUnit(const Terminator &, bool forChildIo = false);
|
||||
static ExternalFileUnit &NewUnit(const Terminator &, bool forChildIo);
|
||||
static void CloseAll(IoErrorHandler &);
|
||||
static void FlushAll(IoErrorHandler &);
|
||||
|
||||
|
|
Loading…
Reference in New Issue