forked from llvm/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathunit.h
294 lines (261 loc) · 11.7 KB
/
unit.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
//===-- runtime/unit.h ------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Fortran external I/O units
#ifndef FORTRAN_RUNTIME_IO_UNIT_H_
#define FORTRAN_RUNTIME_IO_UNIT_H_
#include "buffer.h"
#include "connection.h"
#include "environment.h"
#include "file.h"
#include "format.h"
#include "io-error.h"
#include "io-stmt.h"
#include "lock.h"
#include "terminator.h"
#include "flang/Common/constexpr-bitset.h"
#include "flang/Common/optional.h"
#include "flang/Runtime/memory.h"
#include <cstdlib>
#include <cstring>
#include <flang/Common/variant.h>
namespace Fortran::runtime::io {
class UnitMap;
class ChildIo;
class ExternalFileUnit;
RT_OFFLOAD_VAR_GROUP_BEGIN
// Predefined file units.
extern RT_VAR_ATTRS ExternalFileUnit *defaultInput; // unit 5
extern RT_VAR_ATTRS ExternalFileUnit *defaultOutput; // unit 6
extern RT_VAR_ATTRS ExternalFileUnit *errorOutput; // unit 0 extension
RT_OFFLOAD_VAR_GROUP_END
#if defined(RT_USE_PSEUDO_FILE_UNIT)
// A flavor of OpenFile class that pretends to be a terminal,
// and only provides basic buffering of the output
// in an internal buffer, and Write's the output
// using std::printf(). Since it does not rely on file system
// APIs, it can be used to implement external output
// for offload devices.
class PseudoOpenFile {
public:
using FileOffset = std::int64_t;
RT_API_ATTRS const char *path() const { return nullptr; }
RT_API_ATTRS std::size_t pathLength() const { return 0; }
RT_API_ATTRS void set_path(OwningPtr<char> &&, std::size_t bytes) {}
RT_API_ATTRS bool mayRead() const { return false; }
RT_API_ATTRS bool mayWrite() const { return true; }
RT_API_ATTRS bool mayPosition() const { return false; }
RT_API_ATTRS bool mayAsynchronous() const { return false; }
RT_API_ATTRS void set_mayAsynchronous(bool yes);
// Pretend to be a terminal to force the output
// at the end of IO statement.
RT_API_ATTRS bool isTerminal() const { return true; }
RT_API_ATTRS bool isWindowsTextFile() const { return false; }
RT_API_ATTRS Fortran::common::optional<FileOffset> knownSize() const;
RT_API_ATTRS bool IsConnected() const { return false; }
RT_API_ATTRS void Open(OpenStatus, Fortran::common::optional<Action>,
Position, IoErrorHandler &);
RT_API_ATTRS void Predefine(int fd) {}
RT_API_ATTRS void Close(CloseStatus, IoErrorHandler &);
RT_API_ATTRS std::size_t Read(FileOffset, char *, std::size_t minBytes,
std::size_t maxBytes, IoErrorHandler &);
RT_API_ATTRS std::size_t Write(
FileOffset, const char *, std::size_t, IoErrorHandler &);
RT_API_ATTRS void Truncate(FileOffset, IoErrorHandler &);
RT_API_ATTRS int ReadAsynchronously(
FileOffset, char *, std::size_t, IoErrorHandler &);
RT_API_ATTRS int WriteAsynchronously(
FileOffset, const char *, std::size_t, IoErrorHandler &);
RT_API_ATTRS void Wait(int id, IoErrorHandler &);
RT_API_ATTRS void WaitAll(IoErrorHandler &);
RT_API_ATTRS Position InquirePosition() const;
};
#endif // defined(RT_USE_PSEUDO_FILE_UNIT)
#if !defined(RT_USE_PSEUDO_FILE_UNIT)
using OpenFileClass = OpenFile;
using FileFrameClass = FileFrame<ExternalFileUnit>;
#else // defined(RT_USE_PSEUDO_FILE_UNIT)
using OpenFileClass = PseudoOpenFile;
// Use not so big buffer for the pseudo file unit frame.
using FileFrameClass = FileFrame<ExternalFileUnit, 1024>;
#endif // defined(RT_USE_PSEUDO_FILE_UNIT)
class ExternalFileUnit : public ConnectionState,
public OpenFileClass,
public FileFrameClass {
public:
static constexpr int maxAsyncIds{64 * 16};
explicit RT_API_ATTRS ExternalFileUnit(int unitNumber)
: unitNumber_{unitNumber} {
isUTF8 = executionEnvironment.defaultUTF8;
for (int j{0}; 64 * j < maxAsyncIds; ++j) {
asyncIdAvailable_[j].set();
}
asyncIdAvailable_[0].reset(0);
}
RT_API_ATTRS ~ExternalFileUnit() {}
RT_API_ATTRS int unitNumber() const { return unitNumber_; }
RT_API_ATTRS bool swapEndianness() const { return swapEndianness_; }
RT_API_ATTRS bool createdForInternalChildIo() const {
return createdForInternalChildIo_;
}
static RT_API_ATTRS ExternalFileUnit *LookUp(int unit);
static RT_API_ATTRS ExternalFileUnit *LookUpOrCreate(
int unit, const Terminator &, bool &wasExtant);
static RT_API_ATTRS ExternalFileUnit *LookUpOrCreateAnonymous(int unit,
Direction, Fortran::common::optional<bool> isUnformatted,
IoErrorHandler &);
static RT_API_ATTRS ExternalFileUnit *LookUp(
const char *path, std::size_t pathLen);
static RT_API_ATTRS ExternalFileUnit &CreateNew(int unit, const Terminator &);
static RT_API_ATTRS ExternalFileUnit *LookUpForClose(int unit);
static RT_API_ATTRS ExternalFileUnit &NewUnit(
const Terminator &, bool forChildIo);
static RT_API_ATTRS void CloseAll(IoErrorHandler &);
static RT_API_ATTRS void FlushAll(IoErrorHandler &);
// Returns true if an existing unit was closed
RT_API_ATTRS bool OpenUnit(Fortran::common::optional<OpenStatus>,
Fortran::common::optional<Action>, Position, OwningPtr<char> &&path,
std::size_t pathLength, Convert, IoErrorHandler &);
RT_API_ATTRS bool OpenAnonymousUnit(Fortran::common::optional<OpenStatus>,
Fortran::common::optional<Action>, Position, Convert, IoErrorHandler &);
RT_API_ATTRS void CloseUnit(CloseStatus, IoErrorHandler &);
RT_API_ATTRS void DestroyClosed();
RT_API_ATTRS Iostat SetDirection(Direction);
template <typename A, typename... X>
RT_API_ATTRS IoStatementState &BeginIoStatement(
const Terminator &terminator, X &&...xs) {
// Take lock_ and hold it until EndIoStatement().
#if USE_PTHREADS
if (!lock_.TakeIfNoDeadlock()) {
terminator.Crash("Recursive I/O attempted on unit %d", unitNumber_);
}
#else
lock_.Take();
#endif
A &state{u_.emplace<A>(std::forward<X>(xs)...)};
if constexpr (!std::is_same_v<A, OpenStatementState>) {
state.mutableModes() = ConnectionState::modes;
}
directAccessRecWasSet_ = false;
io_.emplace(state);
return *io_;
}
RT_API_ATTRS bool Emit(
const char *, std::size_t, std::size_t elementBytes, IoErrorHandler &);
RT_API_ATTRS bool Receive(
char *, std::size_t, std::size_t elementBytes, IoErrorHandler &);
RT_API_ATTRS std::size_t GetNextInputBytes(const char *&, IoErrorHandler &);
RT_API_ATTRS std::size_t ViewBytesInRecord(const char *&, bool forward) const;
RT_API_ATTRS bool BeginReadingRecord(IoErrorHandler &);
RT_API_ATTRS void FinishReadingRecord(IoErrorHandler &);
RT_API_ATTRS bool AdvanceRecord(IoErrorHandler &);
RT_API_ATTRS void BackspaceRecord(IoErrorHandler &);
RT_API_ATTRS void FlushOutput(IoErrorHandler &);
RT_API_ATTRS void FlushIfTerminal(IoErrorHandler &);
RT_API_ATTRS void Endfile(IoErrorHandler &);
RT_API_ATTRS void Rewind(IoErrorHandler &);
RT_API_ATTRS void EndIoStatement();
RT_API_ATTRS bool SetStreamPos(
std::int64_t, IoErrorHandler &); // one-based, for POS=
RT_API_ATTRS bool SetDirectRec(
std::int64_t, IoErrorHandler &); // one-based, for REC=
RT_API_ATTRS std::int64_t InquirePos() const {
// 12.6.2.11 defines POS=1 as the beginning of file
return frameOffsetInFile_ + recordOffsetInFrame_ + positionInRecord + 1;
}
RT_API_ATTRS ChildIo *GetChildIo() { return child_.get(); }
RT_API_ATTRS ChildIo &PushChildIo(IoStatementState &);
RT_API_ATTRS void PopChildIo(ChildIo &);
RT_API_ATTRS int GetAsynchronousId(IoErrorHandler &);
RT_API_ATTRS bool Wait(int);
private:
static RT_API_ATTRS UnitMap &CreateUnitMap();
static RT_API_ATTRS UnitMap &GetUnitMap();
RT_API_ATTRS const char *FrameNextInput(IoErrorHandler &, std::size_t);
RT_API_ATTRS void SetPosition(std::int64_t, IoErrorHandler &); // zero-based
RT_API_ATTRS void BeginSequentialVariableUnformattedInputRecord(
IoErrorHandler &);
RT_API_ATTRS void BeginVariableFormattedInputRecord(IoErrorHandler &);
RT_API_ATTRS void BackspaceFixedRecord(IoErrorHandler &);
RT_API_ATTRS void BackspaceVariableUnformattedRecord(IoErrorHandler &);
RT_API_ATTRS void BackspaceVariableFormattedRecord(IoErrorHandler &);
RT_API_ATTRS bool SetVariableFormattedRecordLength();
RT_API_ATTRS void DoImpliedEndfile(IoErrorHandler &);
template <bool ANY_DIR = true, Direction DIR = Direction::Output>
RT_API_ATTRS void DoEndfile(IoErrorHandler &);
RT_API_ATTRS void CommitWrites();
RT_API_ATTRS bool CheckDirectAccess(IoErrorHandler &);
RT_API_ATTRS void HitEndOnRead(IoErrorHandler &);
RT_API_ATTRS std::int32_t ReadHeaderOrFooter(std::int64_t frameOffset);
Lock lock_;
int unitNumber_{-1};
Direction direction_{Direction::Output};
bool impliedEndfile_{false}; // sequential/stream output has taken place
bool beganReadingRecord_{false};
bool anyWriteSinceLastPositioning_{false};
bool directAccessRecWasSet_{false}; // REC= appeared
// Subtle: The beginning of the frame can't be allowed to advance
// during a single list-directed READ due to the possibility of a
// multi-record CHARACTER value with a "r*" repeat count. So we
// manage the frame and the current record therein separately.
std::int64_t frameOffsetInFile_{0};
std::size_t recordOffsetInFrame_{0}; // of currentRecordNumber
bool swapEndianness_{false};
bool createdForInternalChildIo_{false};
common::BitSet<64> asyncIdAvailable_[maxAsyncIds / 64];
// When a synchronous I/O statement is in progress on this unit, holds its
// state.
std::variant<std::monostate, OpenStatementState, CloseStatementState,
ExternalFormattedIoStatementState<Direction::Output>,
ExternalFormattedIoStatementState<Direction::Input>,
ExternalListIoStatementState<Direction::Output>,
ExternalListIoStatementState<Direction::Input>,
ExternalUnformattedIoStatementState<Direction::Output>,
ExternalUnformattedIoStatementState<Direction::Input>, InquireUnitState,
ExternalMiscIoStatementState, ErroneousIoStatementState>
u_;
// Points to the active alternative (if any) in u_ for use as a Cookie
Fortran::common::optional<IoStatementState> io_;
// A stack of child I/O pseudo-units for defined I/O that have this
// unit number.
OwningPtr<ChildIo> child_;
};
// A pseudo-unit for child I/O statements in defined I/O subroutines;
// it forwards operations to the parent I/O statement, which might also
// be a child I/O statement.
class ChildIo {
public:
RT_API_ATTRS ChildIo(IoStatementState &parent, OwningPtr<ChildIo> &&previous)
: parent_{parent}, previous_{std::move(previous)} {}
RT_API_ATTRS IoStatementState &parent() const { return parent_; }
RT_API_ATTRS void EndIoStatement();
template <typename A, typename... X>
RT_API_ATTRS IoStatementState &BeginIoStatement(X &&...xs) {
A &state{u_.emplace<A>(std::forward<X>(xs)...)};
io_.emplace(state);
return *io_;
}
RT_API_ATTRS OwningPtr<ChildIo> AcquirePrevious() {
return std::move(previous_);
}
RT_API_ATTRS Iostat CheckFormattingAndDirection(bool unformatted, Direction);
private:
IoStatementState &parent_;
OwningPtr<ChildIo> previous_;
std::variant<std::monostate,
ChildFormattedIoStatementState<Direction::Output>,
ChildFormattedIoStatementState<Direction::Input>,
ChildListIoStatementState<Direction::Output>,
ChildListIoStatementState<Direction::Input>,
ChildUnformattedIoStatementState<Direction::Output>,
ChildUnformattedIoStatementState<Direction::Input>, InquireUnitState,
ErroneousIoStatementState, ExternalMiscIoStatementState>
u_;
Fortran::common::optional<IoStatementState> io_;
};
} // namespace Fortran::runtime::io
#endif // FORTRAN_RUNTIME_IO_UNIT_H_