annotate libgfortran/io/unit.c @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1 /* Copyright (C) 2002-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
2 Contributed by Andy Vaught
kono
parents:
diff changeset
3 F2003 I/O support contributed by Jerry DeLisle
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 This file is part of the GNU Fortran runtime library (libgfortran).
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 Libgfortran is free software; you can redistribute it and/or modify
kono
parents:
diff changeset
8 it under the terms of the GNU General Public License as published by
kono
parents:
diff changeset
9 the Free Software Foundation; either version 3, or (at your option)
kono
parents:
diff changeset
10 any later version.
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 Libgfortran is distributed in the hope that it will be useful,
kono
parents:
diff changeset
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
kono
parents:
diff changeset
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
kono
parents:
diff changeset
15 GNU General Public License for more details.
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 Under Section 7 of GPL version 3, you are granted additional
kono
parents:
diff changeset
18 permissions described in the GCC Runtime Library Exception, version
kono
parents:
diff changeset
19 3.1, as published by the Free Software Foundation.
kono
parents:
diff changeset
20
kono
parents:
diff changeset
21 You should have received a copy of the GNU General Public License and
kono
parents:
diff changeset
22 a copy of the GCC Runtime Library Exception along with this program;
kono
parents:
diff changeset
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
kono
parents:
diff changeset
24 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
25
kono
parents:
diff changeset
26 #include "io.h"
kono
parents:
diff changeset
27 #include "fbuf.h"
kono
parents:
diff changeset
28 #include "format.h"
kono
parents:
diff changeset
29 #include "unix.h"
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
30 #include "async.h"
111
kono
parents:
diff changeset
31 #include <string.h>
kono
parents:
diff changeset
32 #include <assert.h>
kono
parents:
diff changeset
33
kono
parents:
diff changeset
34
kono
parents:
diff changeset
35 /* IO locking rules:
kono
parents:
diff changeset
36 UNIT_LOCK is a master lock, protecting UNIT_ROOT tree and UNIT_CACHE.
kono
parents:
diff changeset
37 Concurrent use of different units should be supported, so
kono
parents:
diff changeset
38 each unit has its own lock, LOCK.
kono
parents:
diff changeset
39 Open should be atomic with its reopening of units and list_read.c
kono
parents:
diff changeset
40 in several places needs find_unit another unit while holding stdin
kono
parents:
diff changeset
41 unit's lock, so it must be possible to acquire UNIT_LOCK while holding
kono
parents:
diff changeset
42 some unit's lock. Therefore to avoid deadlocks, it is forbidden
kono
parents:
diff changeset
43 to acquire unit's private locks while holding UNIT_LOCK, except
kono
parents:
diff changeset
44 for freshly created units (where no other thread can get at their
kono
parents:
diff changeset
45 address yet) or when using just trylock rather than lock operation.
kono
parents:
diff changeset
46 In addition to unit's private lock each unit has a WAITERS counter
kono
parents:
diff changeset
47 and CLOSED flag. WAITERS counter must be either only
kono
parents:
diff changeset
48 atomically incremented/decremented in all places (if atomic builtins
kono
parents:
diff changeset
49 are supported), or protected by UNIT_LOCK in all places (otherwise).
kono
parents:
diff changeset
50 CLOSED flag must be always protected by unit's LOCK.
kono
parents:
diff changeset
51 After finding a unit in UNIT_CACHE or UNIT_ROOT with UNIT_LOCK held,
kono
parents:
diff changeset
52 WAITERS must be incremented to avoid concurrent close from freeing
kono
parents:
diff changeset
53 the unit between unlocking UNIT_LOCK and acquiring unit's LOCK.
kono
parents:
diff changeset
54 Unit freeing is always done under UNIT_LOCK. If close_unit sees any
kono
parents:
diff changeset
55 WAITERS, it doesn't free the unit but instead sets the CLOSED flag
kono
parents:
diff changeset
56 and the thread that decrements WAITERS to zero while CLOSED flag is
kono
parents:
diff changeset
57 set is responsible for freeing it (while holding UNIT_LOCK).
kono
parents:
diff changeset
58 flush_all_units operation is iterating over the unit tree with
kono
parents:
diff changeset
59 increasing UNIT_NUMBER while holding UNIT_LOCK and attempting to
kono
parents:
diff changeset
60 flush each unit (and therefore needs the unit's LOCK held as well).
kono
parents:
diff changeset
61 To avoid deadlocks, it just trylocks the LOCK and if unsuccessful,
kono
parents:
diff changeset
62 remembers the current unit's UNIT_NUMBER, unlocks UNIT_LOCK, acquires
kono
parents:
diff changeset
63 unit's LOCK and after flushing reacquires UNIT_LOCK and restarts with
kono
parents:
diff changeset
64 the smallest UNIT_NUMBER above the last one flushed.
kono
parents:
diff changeset
65
kono
parents:
diff changeset
66 If find_unit/find_or_create_unit/find_file/get_unit routines return
kono
parents:
diff changeset
67 non-NULL, the returned unit has its private lock locked and when the
kono
parents:
diff changeset
68 caller is done with it, it must call either unlock_unit or close_unit
kono
parents:
diff changeset
69 on it. unlock_unit or close_unit must be always called only with the
kono
parents:
diff changeset
70 private lock held. */
kono
parents:
diff changeset
71
kono
parents:
diff changeset
72
kono
parents:
diff changeset
73
kono
parents:
diff changeset
74 /* Table of allocated newunit values. A simple solution would be to
kono
parents:
diff changeset
75 map OS file descriptors (fd's) to unit numbers, e.g. with newunit =
kono
parents:
diff changeset
76 -fd - 2, however that doesn't work since Fortran allows an existing
kono
parents:
diff changeset
77 unit number to be reassociated with a new file. Thus the simple
kono
parents:
diff changeset
78 approach may lead to a situation where we'd try to assign a
kono
parents:
diff changeset
79 (negative) unit number which already exists. Hence we must keep
kono
parents:
diff changeset
80 track of allocated newunit values ourselves. This is the purpose of
kono
parents:
diff changeset
81 the newunits array. The indices map to newunit values as newunit =
kono
parents:
diff changeset
82 -index + NEWUNIT_FIRST. E.g. newunits[0] having the value true
kono
parents:
diff changeset
83 means that a unit with number NEWUNIT_FIRST exists. Similar to
kono
parents:
diff changeset
84 POSIX file descriptors, we always allocate the lowest (in absolute
kono
parents:
diff changeset
85 value) available unit number.
kono
parents:
diff changeset
86 */
kono
parents:
diff changeset
87 static bool *newunits;
kono
parents:
diff changeset
88 static int newunit_size; /* Total number of elements in the newunits array. */
kono
parents:
diff changeset
89 /* Low water indicator for the newunits array. Below the LWI all the
kono
parents:
diff changeset
90 units are allocated, above and equal to the LWI there may be both
kono
parents:
diff changeset
91 allocated and free units. */
kono
parents:
diff changeset
92 static int newunit_lwi;
kono
parents:
diff changeset
93
kono
parents:
diff changeset
94 /* Unit numbers assigned with NEWUNIT start from here. */
kono
parents:
diff changeset
95 #define NEWUNIT_START -10
kono
parents:
diff changeset
96
kono
parents:
diff changeset
97 #define CACHE_SIZE 3
kono
parents:
diff changeset
98 static gfc_unit *unit_cache[CACHE_SIZE];
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
99
111
kono
parents:
diff changeset
100 gfc_offset max_offset;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
101 gfc_offset default_recl;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
102
111
kono
parents:
diff changeset
103 gfc_unit *unit_root;
kono
parents:
diff changeset
104 #ifdef __GTHREAD_MUTEX_INIT
kono
parents:
diff changeset
105 __gthread_mutex_t unit_lock = __GTHREAD_MUTEX_INIT;
kono
parents:
diff changeset
106 #else
kono
parents:
diff changeset
107 __gthread_mutex_t unit_lock;
kono
parents:
diff changeset
108 #endif
kono
parents:
diff changeset
109
kono
parents:
diff changeset
110 /* We use these filenames for error reporting. */
kono
parents:
diff changeset
111
kono
parents:
diff changeset
112 static char stdin_name[] = "stdin";
kono
parents:
diff changeset
113 static char stdout_name[] = "stdout";
kono
parents:
diff changeset
114 static char stderr_name[] = "stderr";
kono
parents:
diff changeset
115
kono
parents:
diff changeset
116
kono
parents:
diff changeset
117 #ifdef HAVE_NEWLOCALE
kono
parents:
diff changeset
118 locale_t c_locale;
kono
parents:
diff changeset
119 #else
kono
parents:
diff changeset
120 /* If we don't have POSIX 2008 per-thread locales, we need to use the
kono
parents:
diff changeset
121 traditional setlocale(). To prevent multiple concurrent threads
kono
parents:
diff changeset
122 doing formatted I/O from messing up the locale, we need to store a
kono
parents:
diff changeset
123 global old_locale, and a counter keeping track of how many threads
kono
parents:
diff changeset
124 are currently doing formatted I/O. The first thread saves the old
kono
parents:
diff changeset
125 locale, and the last one restores it. */
kono
parents:
diff changeset
126 char *old_locale;
kono
parents:
diff changeset
127 int old_locale_ctr;
kono
parents:
diff changeset
128 #ifdef __GTHREAD_MUTEX_INIT
kono
parents:
diff changeset
129 __gthread_mutex_t old_locale_lock = __GTHREAD_MUTEX_INIT;
kono
parents:
diff changeset
130 #else
kono
parents:
diff changeset
131 __gthread_mutex_t old_locale_lock;
kono
parents:
diff changeset
132 #endif
kono
parents:
diff changeset
133 #endif
kono
parents:
diff changeset
134
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136 /* This implementation is based on Stefan Nilsson's article in the
kono
parents:
diff changeset
137 July 1997 Doctor Dobb's Journal, "Treaps in Java". */
kono
parents:
diff changeset
138
kono
parents:
diff changeset
139 /* pseudo_random()-- Simple linear congruential pseudorandom number
kono
parents:
diff changeset
140 generator. The period of this generator is 44071, which is plenty
kono
parents:
diff changeset
141 for our purposes. */
kono
parents:
diff changeset
142
kono
parents:
diff changeset
143 static int
kono
parents:
diff changeset
144 pseudo_random (void)
kono
parents:
diff changeset
145 {
kono
parents:
diff changeset
146 static int x0 = 5341;
kono
parents:
diff changeset
147
kono
parents:
diff changeset
148 x0 = (22611 * x0 + 10) % 44071;
kono
parents:
diff changeset
149 return x0;
kono
parents:
diff changeset
150 }
kono
parents:
diff changeset
151
kono
parents:
diff changeset
152
kono
parents:
diff changeset
153 /* rotate_left()-- Rotate the treap left */
kono
parents:
diff changeset
154
kono
parents:
diff changeset
155 static gfc_unit *
kono
parents:
diff changeset
156 rotate_left (gfc_unit *t)
kono
parents:
diff changeset
157 {
kono
parents:
diff changeset
158 gfc_unit *temp;
kono
parents:
diff changeset
159
kono
parents:
diff changeset
160 temp = t->right;
kono
parents:
diff changeset
161 t->right = t->right->left;
kono
parents:
diff changeset
162 temp->left = t;
kono
parents:
diff changeset
163
kono
parents:
diff changeset
164 return temp;
kono
parents:
diff changeset
165 }
kono
parents:
diff changeset
166
kono
parents:
diff changeset
167
kono
parents:
diff changeset
168 /* rotate_right()-- Rotate the treap right */
kono
parents:
diff changeset
169
kono
parents:
diff changeset
170 static gfc_unit *
kono
parents:
diff changeset
171 rotate_right (gfc_unit *t)
kono
parents:
diff changeset
172 {
kono
parents:
diff changeset
173 gfc_unit *temp;
kono
parents:
diff changeset
174
kono
parents:
diff changeset
175 temp = t->left;
kono
parents:
diff changeset
176 t->left = t->left->right;
kono
parents:
diff changeset
177 temp->right = t;
kono
parents:
diff changeset
178
kono
parents:
diff changeset
179 return temp;
kono
parents:
diff changeset
180 }
kono
parents:
diff changeset
181
kono
parents:
diff changeset
182
kono
parents:
diff changeset
183 static int
kono
parents:
diff changeset
184 compare (int a, int b)
kono
parents:
diff changeset
185 {
kono
parents:
diff changeset
186 if (a < b)
kono
parents:
diff changeset
187 return -1;
kono
parents:
diff changeset
188 if (a > b)
kono
parents:
diff changeset
189 return 1;
kono
parents:
diff changeset
190
kono
parents:
diff changeset
191 return 0;
kono
parents:
diff changeset
192 }
kono
parents:
diff changeset
193
kono
parents:
diff changeset
194
kono
parents:
diff changeset
195 /* insert()-- Recursive insertion function. Returns the updated treap. */
kono
parents:
diff changeset
196
kono
parents:
diff changeset
197 static gfc_unit *
kono
parents:
diff changeset
198 insert (gfc_unit *new, gfc_unit *t)
kono
parents:
diff changeset
199 {
kono
parents:
diff changeset
200 int c;
kono
parents:
diff changeset
201
kono
parents:
diff changeset
202 if (t == NULL)
kono
parents:
diff changeset
203 return new;
kono
parents:
diff changeset
204
kono
parents:
diff changeset
205 c = compare (new->unit_number, t->unit_number);
kono
parents:
diff changeset
206
kono
parents:
diff changeset
207 if (c < 0)
kono
parents:
diff changeset
208 {
kono
parents:
diff changeset
209 t->left = insert (new, t->left);
kono
parents:
diff changeset
210 if (t->priority < t->left->priority)
kono
parents:
diff changeset
211 t = rotate_right (t);
kono
parents:
diff changeset
212 }
kono
parents:
diff changeset
213
kono
parents:
diff changeset
214 if (c > 0)
kono
parents:
diff changeset
215 {
kono
parents:
diff changeset
216 t->right = insert (new, t->right);
kono
parents:
diff changeset
217 if (t->priority < t->right->priority)
kono
parents:
diff changeset
218 t = rotate_left (t);
kono
parents:
diff changeset
219 }
kono
parents:
diff changeset
220
kono
parents:
diff changeset
221 if (c == 0)
kono
parents:
diff changeset
222 internal_error (NULL, "insert(): Duplicate key found!");
kono
parents:
diff changeset
223
kono
parents:
diff changeset
224 return t;
kono
parents:
diff changeset
225 }
kono
parents:
diff changeset
226
kono
parents:
diff changeset
227
kono
parents:
diff changeset
228 /* insert_unit()-- Create a new node, insert it into the treap. */
kono
parents:
diff changeset
229
kono
parents:
diff changeset
230 static gfc_unit *
kono
parents:
diff changeset
231 insert_unit (int n)
kono
parents:
diff changeset
232 {
kono
parents:
diff changeset
233 gfc_unit *u = xcalloc (1, sizeof (gfc_unit));
kono
parents:
diff changeset
234 u->unit_number = n;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
235 u->internal_unit_kind = 0;
111
kono
parents:
diff changeset
236 #ifdef __GTHREAD_MUTEX_INIT
kono
parents:
diff changeset
237 {
kono
parents:
diff changeset
238 __gthread_mutex_t tmp = __GTHREAD_MUTEX_INIT;
kono
parents:
diff changeset
239 u->lock = tmp;
kono
parents:
diff changeset
240 }
kono
parents:
diff changeset
241 #else
kono
parents:
diff changeset
242 __GTHREAD_MUTEX_INIT_FUNCTION (&u->lock);
kono
parents:
diff changeset
243 #endif
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
244 LOCK (&u->lock);
111
kono
parents:
diff changeset
245 u->priority = pseudo_random ();
kono
parents:
diff changeset
246 unit_root = insert (u, unit_root);
kono
parents:
diff changeset
247 return u;
kono
parents:
diff changeset
248 }
kono
parents:
diff changeset
249
kono
parents:
diff changeset
250
kono
parents:
diff changeset
251 /* destroy_unit_mutex()-- Destroy the mutex and free memory of unit. */
kono
parents:
diff changeset
252
kono
parents:
diff changeset
253 static void
kono
parents:
diff changeset
254 destroy_unit_mutex (gfc_unit *u)
kono
parents:
diff changeset
255 {
kono
parents:
diff changeset
256 __gthread_mutex_destroy (&u->lock);
kono
parents:
diff changeset
257 free (u);
kono
parents:
diff changeset
258 }
kono
parents:
diff changeset
259
kono
parents:
diff changeset
260
kono
parents:
diff changeset
261 static gfc_unit *
kono
parents:
diff changeset
262 delete_root (gfc_unit *t)
kono
parents:
diff changeset
263 {
kono
parents:
diff changeset
264 gfc_unit *temp;
kono
parents:
diff changeset
265
kono
parents:
diff changeset
266 if (t->left == NULL)
kono
parents:
diff changeset
267 return t->right;
kono
parents:
diff changeset
268 if (t->right == NULL)
kono
parents:
diff changeset
269 return t->left;
kono
parents:
diff changeset
270
kono
parents:
diff changeset
271 if (t->left->priority > t->right->priority)
kono
parents:
diff changeset
272 {
kono
parents:
diff changeset
273 temp = rotate_right (t);
kono
parents:
diff changeset
274 temp->right = delete_root (t);
kono
parents:
diff changeset
275 }
kono
parents:
diff changeset
276 else
kono
parents:
diff changeset
277 {
kono
parents:
diff changeset
278 temp = rotate_left (t);
kono
parents:
diff changeset
279 temp->left = delete_root (t);
kono
parents:
diff changeset
280 }
kono
parents:
diff changeset
281
kono
parents:
diff changeset
282 return temp;
kono
parents:
diff changeset
283 }
kono
parents:
diff changeset
284
kono
parents:
diff changeset
285
kono
parents:
diff changeset
286 /* delete_treap()-- Delete an element from a tree. The 'old' value
kono
parents:
diff changeset
287 does not necessarily have to point to the element to be deleted, it
kono
parents:
diff changeset
288 must just point to a treap structure with the key to be deleted.
kono
parents:
diff changeset
289 Returns the new root node of the tree. */
kono
parents:
diff changeset
290
kono
parents:
diff changeset
291 static gfc_unit *
kono
parents:
diff changeset
292 delete_treap (gfc_unit *old, gfc_unit *t)
kono
parents:
diff changeset
293 {
kono
parents:
diff changeset
294 int c;
kono
parents:
diff changeset
295
kono
parents:
diff changeset
296 if (t == NULL)
kono
parents:
diff changeset
297 return NULL;
kono
parents:
diff changeset
298
kono
parents:
diff changeset
299 c = compare (old->unit_number, t->unit_number);
kono
parents:
diff changeset
300
kono
parents:
diff changeset
301 if (c < 0)
kono
parents:
diff changeset
302 t->left = delete_treap (old, t->left);
kono
parents:
diff changeset
303 if (c > 0)
kono
parents:
diff changeset
304 t->right = delete_treap (old, t->right);
kono
parents:
diff changeset
305 if (c == 0)
kono
parents:
diff changeset
306 t = delete_root (t);
kono
parents:
diff changeset
307
kono
parents:
diff changeset
308 return t;
kono
parents:
diff changeset
309 }
kono
parents:
diff changeset
310
kono
parents:
diff changeset
311
kono
parents:
diff changeset
312 /* delete_unit()-- Delete a unit from a tree */
kono
parents:
diff changeset
313
kono
parents:
diff changeset
314 static void
kono
parents:
diff changeset
315 delete_unit (gfc_unit *old)
kono
parents:
diff changeset
316 {
kono
parents:
diff changeset
317 unit_root = delete_treap (old, unit_root);
kono
parents:
diff changeset
318 }
kono
parents:
diff changeset
319
kono
parents:
diff changeset
320
kono
parents:
diff changeset
321 /* get_gfc_unit()-- Given an integer, return a pointer to the unit
kono
parents:
diff changeset
322 structure. Returns NULL if the unit does not exist,
kono
parents:
diff changeset
323 otherwise returns a locked unit. */
kono
parents:
diff changeset
324
kono
parents:
diff changeset
325 static gfc_unit *
kono
parents:
diff changeset
326 get_gfc_unit (int n, int do_create)
kono
parents:
diff changeset
327 {
kono
parents:
diff changeset
328 gfc_unit *p;
kono
parents:
diff changeset
329 int c, created = 0;
kono
parents:
diff changeset
330
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
331 NOTE ("Unit n=%d, do_create = %d", n, do_create);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
332 LOCK (&unit_lock);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
333
111
kono
parents:
diff changeset
334 retry:
kono
parents:
diff changeset
335 for (c = 0; c < CACHE_SIZE; c++)
kono
parents:
diff changeset
336 if (unit_cache[c] != NULL && unit_cache[c]->unit_number == n)
kono
parents:
diff changeset
337 {
kono
parents:
diff changeset
338 p = unit_cache[c];
kono
parents:
diff changeset
339 goto found;
kono
parents:
diff changeset
340 }
kono
parents:
diff changeset
341
kono
parents:
diff changeset
342 p = unit_root;
kono
parents:
diff changeset
343 while (p != NULL)
kono
parents:
diff changeset
344 {
kono
parents:
diff changeset
345 c = compare (n, p->unit_number);
kono
parents:
diff changeset
346 if (c < 0)
kono
parents:
diff changeset
347 p = p->left;
kono
parents:
diff changeset
348 if (c > 0)
kono
parents:
diff changeset
349 p = p->right;
kono
parents:
diff changeset
350 if (c == 0)
kono
parents:
diff changeset
351 break;
kono
parents:
diff changeset
352 }
kono
parents:
diff changeset
353
kono
parents:
diff changeset
354 if (p == NULL && do_create)
kono
parents:
diff changeset
355 {
kono
parents:
diff changeset
356 p = insert_unit (n);
kono
parents:
diff changeset
357 created = 1;
kono
parents:
diff changeset
358 }
kono
parents:
diff changeset
359
kono
parents:
diff changeset
360 if (p != NULL)
kono
parents:
diff changeset
361 {
kono
parents:
diff changeset
362 for (c = 0; c < CACHE_SIZE - 1; c++)
kono
parents:
diff changeset
363 unit_cache[c] = unit_cache[c + 1];
kono
parents:
diff changeset
364
kono
parents:
diff changeset
365 unit_cache[CACHE_SIZE - 1] = p;
kono
parents:
diff changeset
366 }
kono
parents:
diff changeset
367
kono
parents:
diff changeset
368 if (created)
kono
parents:
diff changeset
369 {
kono
parents:
diff changeset
370 /* Newly created units have their lock held already
kono
parents:
diff changeset
371 from insert_unit. Just unlock UNIT_LOCK and return. */
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
372 UNLOCK (&unit_lock);
111
kono
parents:
diff changeset
373 return p;
kono
parents:
diff changeset
374 }
kono
parents:
diff changeset
375
kono
parents:
diff changeset
376 found:
kono
parents:
diff changeset
377 if (p != NULL && (p->child_dtio == 0))
kono
parents:
diff changeset
378 {
kono
parents:
diff changeset
379 /* Fast path. */
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
380 if (! TRYLOCK (&p->lock))
111
kono
parents:
diff changeset
381 {
kono
parents:
diff changeset
382 /* assert (p->closed == 0); */
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
383 UNLOCK (&unit_lock);
111
kono
parents:
diff changeset
384 return p;
kono
parents:
diff changeset
385 }
kono
parents:
diff changeset
386
kono
parents:
diff changeset
387 inc_waiting_locked (p);
kono
parents:
diff changeset
388 }
kono
parents:
diff changeset
389
kono
parents:
diff changeset
390
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
391 UNLOCK (&unit_lock);
111
kono
parents:
diff changeset
392
kono
parents:
diff changeset
393 if (p != NULL && (p->child_dtio == 0))
kono
parents:
diff changeset
394 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
395 LOCK (&p->lock);
111
kono
parents:
diff changeset
396 if (p->closed)
kono
parents:
diff changeset
397 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
398 LOCK (&unit_lock);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
399 UNLOCK (&p->lock);
111
kono
parents:
diff changeset
400 if (predec_waiting_locked (p) == 0)
kono
parents:
diff changeset
401 destroy_unit_mutex (p);
kono
parents:
diff changeset
402 goto retry;
kono
parents:
diff changeset
403 }
kono
parents:
diff changeset
404
kono
parents:
diff changeset
405 dec_waiting_unlocked (p);
kono
parents:
diff changeset
406 }
kono
parents:
diff changeset
407 return p;
kono
parents:
diff changeset
408 }
kono
parents:
diff changeset
409
kono
parents:
diff changeset
410
kono
parents:
diff changeset
411 gfc_unit *
kono
parents:
diff changeset
412 find_unit (int n)
kono
parents:
diff changeset
413 {
kono
parents:
diff changeset
414 return get_gfc_unit (n, 0);
kono
parents:
diff changeset
415 }
kono
parents:
diff changeset
416
kono
parents:
diff changeset
417
kono
parents:
diff changeset
418 gfc_unit *
kono
parents:
diff changeset
419 find_or_create_unit (int n)
kono
parents:
diff changeset
420 {
kono
parents:
diff changeset
421 return get_gfc_unit (n, 1);
kono
parents:
diff changeset
422 }
kono
parents:
diff changeset
423
kono
parents:
diff changeset
424
kono
parents:
diff changeset
425 /* Helper function to check rank, stride, format string, and namelist.
kono
parents:
diff changeset
426 This is used for optimization. You can't trim out blanks or shorten
kono
parents:
diff changeset
427 the string if trailing spaces are significant. */
kono
parents:
diff changeset
428 static bool
kono
parents:
diff changeset
429 is_trim_ok (st_parameter_dt *dtp)
kono
parents:
diff changeset
430 {
kono
parents:
diff changeset
431 /* Check rank and stride. */
kono
parents:
diff changeset
432 if (dtp->internal_unit_desc)
kono
parents:
diff changeset
433 return false;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
434 /* Format strings cannot have 'BZ' or '/'. */
111
kono
parents:
diff changeset
435 if (dtp->common.flags & IOPARM_DT_HAS_FORMAT)
kono
parents:
diff changeset
436 {
kono
parents:
diff changeset
437 char *p = dtp->format;
kono
parents:
diff changeset
438 if (dtp->common.flags & IOPARM_DT_HAS_BLANK)
kono
parents:
diff changeset
439 return false;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
440 for (gfc_charlen_type i = 0; i < dtp->format_len; i++)
111
kono
parents:
diff changeset
441 {
kono
parents:
diff changeset
442 if (p[i] == '/') return false;
kono
parents:
diff changeset
443 if (p[i] == 'b' || p[i] == 'B')
kono
parents:
diff changeset
444 if (p[i+1] == 'z' || p[i+1] == 'Z')
kono
parents:
diff changeset
445 return false;
kono
parents:
diff changeset
446 }
kono
parents:
diff changeset
447 }
kono
parents:
diff changeset
448 if (dtp->u.p.ionml) /* A namelist. */
kono
parents:
diff changeset
449 return false;
kono
parents:
diff changeset
450 return true;
kono
parents:
diff changeset
451 }
kono
parents:
diff changeset
452
kono
parents:
diff changeset
453
kono
parents:
diff changeset
454 gfc_unit *
kono
parents:
diff changeset
455 set_internal_unit (st_parameter_dt *dtp, gfc_unit *iunit, int kind)
kono
parents:
diff changeset
456 {
kono
parents:
diff changeset
457 gfc_offset start_record = 0;
kono
parents:
diff changeset
458
kono
parents:
diff changeset
459 iunit->unit_number = dtp->common.unit;
kono
parents:
diff changeset
460 iunit->recl = dtp->internal_unit_len;
kono
parents:
diff changeset
461 iunit->internal_unit = dtp->internal_unit;
kono
parents:
diff changeset
462 iunit->internal_unit_len = dtp->internal_unit_len;
kono
parents:
diff changeset
463 iunit->internal_unit_kind = kind;
kono
parents:
diff changeset
464
kono
parents:
diff changeset
465 /* As an optimization, adjust the unit record length to not
kono
parents:
diff changeset
466 include trailing blanks. This will not work under certain conditions
kono
parents:
diff changeset
467 where trailing blanks have significance. */
kono
parents:
diff changeset
468 if (dtp->u.p.mode == READING && is_trim_ok (dtp))
kono
parents:
diff changeset
469 {
kono
parents:
diff changeset
470 int len;
kono
parents:
diff changeset
471 if (kind == 1)
kono
parents:
diff changeset
472 len = string_len_trim (iunit->internal_unit_len,
kono
parents:
diff changeset
473 iunit->internal_unit);
kono
parents:
diff changeset
474 else
kono
parents:
diff changeset
475 len = string_len_trim_char4 (iunit->internal_unit_len,
kono
parents:
diff changeset
476 (const gfc_char4_t*) iunit->internal_unit);
kono
parents:
diff changeset
477 iunit->internal_unit_len = len;
kono
parents:
diff changeset
478 iunit->recl = iunit->internal_unit_len;
kono
parents:
diff changeset
479 }
kono
parents:
diff changeset
480
kono
parents:
diff changeset
481 /* Set up the looping specification from the array descriptor, if any. */
kono
parents:
diff changeset
482
kono
parents:
diff changeset
483 if (is_array_io (dtp))
kono
parents:
diff changeset
484 {
kono
parents:
diff changeset
485 iunit->rank = GFC_DESCRIPTOR_RANK (dtp->internal_unit_desc);
kono
parents:
diff changeset
486 iunit->ls = (array_loop_spec *)
kono
parents:
diff changeset
487 xmallocarray (iunit->rank, sizeof (array_loop_spec));
kono
parents:
diff changeset
488 iunit->internal_unit_len *=
kono
parents:
diff changeset
489 init_loop_spec (dtp->internal_unit_desc, iunit->ls, &start_record);
kono
parents:
diff changeset
490
kono
parents:
diff changeset
491 start_record *= iunit->recl;
kono
parents:
diff changeset
492 }
kono
parents:
diff changeset
493
kono
parents:
diff changeset
494 /* Set initial values for unit parameters. */
kono
parents:
diff changeset
495 if (kind == 4)
kono
parents:
diff changeset
496 iunit->s = open_internal4 (iunit->internal_unit - start_record,
kono
parents:
diff changeset
497 iunit->internal_unit_len, -start_record);
kono
parents:
diff changeset
498 else
kono
parents:
diff changeset
499 iunit->s = open_internal (iunit->internal_unit - start_record,
kono
parents:
diff changeset
500 iunit->internal_unit_len, -start_record);
kono
parents:
diff changeset
501
kono
parents:
diff changeset
502 iunit->bytes_left = iunit->recl;
kono
parents:
diff changeset
503 iunit->last_record=0;
kono
parents:
diff changeset
504 iunit->maxrec=0;
kono
parents:
diff changeset
505 iunit->current_record=0;
kono
parents:
diff changeset
506 iunit->read_bad = 0;
kono
parents:
diff changeset
507 iunit->endfile = NO_ENDFILE;
kono
parents:
diff changeset
508
kono
parents:
diff changeset
509 /* Set flags for the internal unit. */
kono
parents:
diff changeset
510
kono
parents:
diff changeset
511 iunit->flags.access = ACCESS_SEQUENTIAL;
kono
parents:
diff changeset
512 iunit->flags.action = ACTION_READWRITE;
kono
parents:
diff changeset
513 iunit->flags.blank = BLANK_NULL;
kono
parents:
diff changeset
514 iunit->flags.form = FORM_FORMATTED;
kono
parents:
diff changeset
515 iunit->flags.pad = PAD_YES;
kono
parents:
diff changeset
516 iunit->flags.status = STATUS_UNSPECIFIED;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
517 iunit->flags.sign = SIGN_PROCDEFINED;
111
kono
parents:
diff changeset
518 iunit->flags.decimal = DECIMAL_POINT;
kono
parents:
diff changeset
519 iunit->flags.delim = DELIM_UNSPECIFIED;
kono
parents:
diff changeset
520 iunit->flags.encoding = ENCODING_DEFAULT;
kono
parents:
diff changeset
521 iunit->flags.async = ASYNC_NO;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
522 iunit->flags.round = ROUND_PROCDEFINED;
111
kono
parents:
diff changeset
523
kono
parents:
diff changeset
524 /* Initialize the data transfer parameters. */
kono
parents:
diff changeset
525
kono
parents:
diff changeset
526 dtp->u.p.advance_status = ADVANCE_YES;
kono
parents:
diff changeset
527 dtp->u.p.seen_dollar = 0;
kono
parents:
diff changeset
528 dtp->u.p.skips = 0;
kono
parents:
diff changeset
529 dtp->u.p.pending_spaces = 0;
kono
parents:
diff changeset
530 dtp->u.p.max_pos = 0;
kono
parents:
diff changeset
531 dtp->u.p.at_eof = 0;
kono
parents:
diff changeset
532 return iunit;
kono
parents:
diff changeset
533 }
kono
parents:
diff changeset
534
kono
parents:
diff changeset
535
kono
parents:
diff changeset
536 /* get_unit()-- Returns the unit structure associated with the integer
kono
parents:
diff changeset
537 unit or the internal file. */
kono
parents:
diff changeset
538
kono
parents:
diff changeset
539 gfc_unit *
kono
parents:
diff changeset
540 get_unit (st_parameter_dt *dtp, int do_create)
kono
parents:
diff changeset
541 {
kono
parents:
diff changeset
542 gfc_unit *unit;
kono
parents:
diff changeset
543
kono
parents:
diff changeset
544 if ((dtp->common.flags & IOPARM_DT_HAS_INTERNAL_UNIT) != 0)
kono
parents:
diff changeset
545 {
kono
parents:
diff changeset
546 int kind;
kono
parents:
diff changeset
547 if (dtp->common.unit == GFC_INTERNAL_UNIT)
kono
parents:
diff changeset
548 kind = 1;
kono
parents:
diff changeset
549 else if (dtp->common.unit == GFC_INTERNAL_UNIT4)
kono
parents:
diff changeset
550 kind = 4;
kono
parents:
diff changeset
551 else
kono
parents:
diff changeset
552 internal_error (&dtp->common, "get_unit(): Bad internal unit KIND");
kono
parents:
diff changeset
553
kono
parents:
diff changeset
554 dtp->u.p.unit_is_internal = 1;
kono
parents:
diff changeset
555 dtp->common.unit = newunit_alloc ();
kono
parents:
diff changeset
556 unit = get_gfc_unit (dtp->common.unit, do_create);
kono
parents:
diff changeset
557 set_internal_unit (dtp, unit, kind);
kono
parents:
diff changeset
558 fbuf_init (unit, 128);
kono
parents:
diff changeset
559 return unit;
kono
parents:
diff changeset
560 }
kono
parents:
diff changeset
561
kono
parents:
diff changeset
562 /* Has to be an external unit. */
kono
parents:
diff changeset
563 dtp->u.p.unit_is_internal = 0;
kono
parents:
diff changeset
564 dtp->internal_unit = NULL;
kono
parents:
diff changeset
565 dtp->internal_unit_desc = NULL;
kono
parents:
diff changeset
566
kono
parents:
diff changeset
567 /* For an external unit with unit number < 0 creating it on the fly
kono
parents:
diff changeset
568 is not allowed, such units must be created with
kono
parents:
diff changeset
569 OPEN(NEWUNIT=...). */
kono
parents:
diff changeset
570 if (dtp->common.unit < 0)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
571 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
572 if (dtp->common.unit > NEWUNIT_START) /* Reserved units. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
573 return NULL;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
574 return get_gfc_unit (dtp->common.unit, 0);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
575 }
111
kono
parents:
diff changeset
576
kono
parents:
diff changeset
577 return get_gfc_unit (dtp->common.unit, do_create);
kono
parents:
diff changeset
578 }
kono
parents:
diff changeset
579
kono
parents:
diff changeset
580
kono
parents:
diff changeset
581 /*************************/
kono
parents:
diff changeset
582 /* Initialize everything. */
kono
parents:
diff changeset
583
kono
parents:
diff changeset
584 void
kono
parents:
diff changeset
585 init_units (void)
kono
parents:
diff changeset
586 {
kono
parents:
diff changeset
587 gfc_unit *u;
kono
parents:
diff changeset
588
kono
parents:
diff changeset
589 #ifdef HAVE_NEWLOCALE
kono
parents:
diff changeset
590 c_locale = newlocale (0, "C", 0);
kono
parents:
diff changeset
591 #else
kono
parents:
diff changeset
592 #ifndef __GTHREAD_MUTEX_INIT
kono
parents:
diff changeset
593 __GTHREAD_MUTEX_INIT_FUNCTION (&old_locale_lock);
kono
parents:
diff changeset
594 #endif
kono
parents:
diff changeset
595 #endif
kono
parents:
diff changeset
596
kono
parents:
diff changeset
597 #ifndef __GTHREAD_MUTEX_INIT
kono
parents:
diff changeset
598 __GTHREAD_MUTEX_INIT_FUNCTION (&unit_lock);
kono
parents:
diff changeset
599 #endif
kono
parents:
diff changeset
600
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
601 if (sizeof (max_offset) == 8)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
602 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
603 max_offset = GFC_INTEGER_8_HUGE;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
604 /* Why this weird value? Because if the recl specifier in the
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
605 inquire statement is a 4 byte value, u->recl is truncated,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
606 and this trick ensures it becomes HUGE(0) rather than -1.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
607 The full 8 byte value of default_recl is still 0.99999999 *
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
608 max_offset which is large enough for all practical
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
609 purposes. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
610 default_recl = max_offset & ~(1LL<<31);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
611 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
612 else if (sizeof (max_offset) == 4)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
613 max_offset = default_recl = GFC_INTEGER_4_HUGE;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
614 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
615 internal_error (NULL, "sizeof (max_offset) must be 4 or 8");
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
616
111
kono
parents:
diff changeset
617 if (options.stdin_unit >= 0)
kono
parents:
diff changeset
618 { /* STDIN */
kono
parents:
diff changeset
619 u = insert_unit (options.stdin_unit);
kono
parents:
diff changeset
620 u->s = input_stream ();
kono
parents:
diff changeset
621
kono
parents:
diff changeset
622 u->flags.action = ACTION_READ;
kono
parents:
diff changeset
623
kono
parents:
diff changeset
624 u->flags.access = ACCESS_SEQUENTIAL;
kono
parents:
diff changeset
625 u->flags.form = FORM_FORMATTED;
kono
parents:
diff changeset
626 u->flags.status = STATUS_OLD;
kono
parents:
diff changeset
627 u->flags.blank = BLANK_NULL;
kono
parents:
diff changeset
628 u->flags.pad = PAD_YES;
kono
parents:
diff changeset
629 u->flags.position = POSITION_ASIS;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
630 u->flags.sign = SIGN_PROCDEFINED;
111
kono
parents:
diff changeset
631 u->flags.decimal = DECIMAL_POINT;
kono
parents:
diff changeset
632 u->flags.delim = DELIM_UNSPECIFIED;
kono
parents:
diff changeset
633 u->flags.encoding = ENCODING_DEFAULT;
kono
parents:
diff changeset
634 u->flags.async = ASYNC_NO;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
635 u->flags.round = ROUND_PROCDEFINED;
111
kono
parents:
diff changeset
636 u->flags.share = SHARE_UNSPECIFIED;
kono
parents:
diff changeset
637 u->flags.cc = CC_LIST;
kono
parents:
diff changeset
638
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
639 u->recl = default_recl;
111
kono
parents:
diff changeset
640 u->endfile = NO_ENDFILE;
kono
parents:
diff changeset
641
kono
parents:
diff changeset
642 u->filename = strdup (stdin_name);
kono
parents:
diff changeset
643
kono
parents:
diff changeset
644 fbuf_init (u, 0);
kono
parents:
diff changeset
645
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
646 UNLOCK (&u->lock);
111
kono
parents:
diff changeset
647 }
kono
parents:
diff changeset
648
kono
parents:
diff changeset
649 if (options.stdout_unit >= 0)
kono
parents:
diff changeset
650 { /* STDOUT */
kono
parents:
diff changeset
651 u = insert_unit (options.stdout_unit);
kono
parents:
diff changeset
652 u->s = output_stream ();
kono
parents:
diff changeset
653
kono
parents:
diff changeset
654 u->flags.action = ACTION_WRITE;
kono
parents:
diff changeset
655
kono
parents:
diff changeset
656 u->flags.access = ACCESS_SEQUENTIAL;
kono
parents:
diff changeset
657 u->flags.form = FORM_FORMATTED;
kono
parents:
diff changeset
658 u->flags.status = STATUS_OLD;
kono
parents:
diff changeset
659 u->flags.blank = BLANK_NULL;
kono
parents:
diff changeset
660 u->flags.position = POSITION_ASIS;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
661 u->flags.sign = SIGN_PROCDEFINED;
111
kono
parents:
diff changeset
662 u->flags.decimal = DECIMAL_POINT;
kono
parents:
diff changeset
663 u->flags.delim = DELIM_UNSPECIFIED;
kono
parents:
diff changeset
664 u->flags.encoding = ENCODING_DEFAULT;
kono
parents:
diff changeset
665 u->flags.async = ASYNC_NO;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
666 u->flags.round = ROUND_PROCDEFINED;
111
kono
parents:
diff changeset
667 u->flags.share = SHARE_UNSPECIFIED;
kono
parents:
diff changeset
668 u->flags.cc = CC_LIST;
kono
parents:
diff changeset
669
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
670 u->recl = default_recl;
111
kono
parents:
diff changeset
671 u->endfile = AT_ENDFILE;
kono
parents:
diff changeset
672
kono
parents:
diff changeset
673 u->filename = strdup (stdout_name);
kono
parents:
diff changeset
674
kono
parents:
diff changeset
675 fbuf_init (u, 0);
kono
parents:
diff changeset
676
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
677 UNLOCK (&u->lock);
111
kono
parents:
diff changeset
678 }
kono
parents:
diff changeset
679
kono
parents:
diff changeset
680 if (options.stderr_unit >= 0)
kono
parents:
diff changeset
681 { /* STDERR */
kono
parents:
diff changeset
682 u = insert_unit (options.stderr_unit);
kono
parents:
diff changeset
683 u->s = error_stream ();
kono
parents:
diff changeset
684
kono
parents:
diff changeset
685 u->flags.action = ACTION_WRITE;
kono
parents:
diff changeset
686
kono
parents:
diff changeset
687 u->flags.access = ACCESS_SEQUENTIAL;
kono
parents:
diff changeset
688 u->flags.form = FORM_FORMATTED;
kono
parents:
diff changeset
689 u->flags.status = STATUS_OLD;
kono
parents:
diff changeset
690 u->flags.blank = BLANK_NULL;
kono
parents:
diff changeset
691 u->flags.position = POSITION_ASIS;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
692 u->flags.sign = SIGN_PROCDEFINED;
111
kono
parents:
diff changeset
693 u->flags.decimal = DECIMAL_POINT;
kono
parents:
diff changeset
694 u->flags.encoding = ENCODING_DEFAULT;
kono
parents:
diff changeset
695 u->flags.async = ASYNC_NO;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
696 u->flags.round = ROUND_PROCDEFINED;
111
kono
parents:
diff changeset
697 u->flags.share = SHARE_UNSPECIFIED;
kono
parents:
diff changeset
698 u->flags.cc = CC_LIST;
kono
parents:
diff changeset
699
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
700 u->recl = default_recl;
111
kono
parents:
diff changeset
701 u->endfile = AT_ENDFILE;
kono
parents:
diff changeset
702
kono
parents:
diff changeset
703 u->filename = strdup (stderr_name);
kono
parents:
diff changeset
704
kono
parents:
diff changeset
705 fbuf_init (u, 256); /* 256 bytes should be enough, probably not doing
kono
parents:
diff changeset
706 any kind of exotic formatting to stderr. */
kono
parents:
diff changeset
707
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
708 UNLOCK (&u->lock);
111
kono
parents:
diff changeset
709 }
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
710 /* The default internal units. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
711 u = insert_unit (GFC_INTERNAL_UNIT);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
712 UNLOCK (&u->lock);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
713 u = insert_unit (GFC_INTERNAL_UNIT4);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
714 UNLOCK (&u->lock);
111
kono
parents:
diff changeset
715 }
kono
parents:
diff changeset
716
kono
parents:
diff changeset
717
kono
parents:
diff changeset
718 static int
kono
parents:
diff changeset
719 close_unit_1 (gfc_unit *u, int locked)
kono
parents:
diff changeset
720 {
kono
parents:
diff changeset
721 int i, rc;
kono
parents:
diff changeset
722
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
723 if (ASYNC_IO && u->au)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
724 async_close (u->au);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
725
111
kono
parents:
diff changeset
726 /* If there are previously written bytes from a write with ADVANCE="no"
kono
parents:
diff changeset
727 Reposition the buffer before closing. */
kono
parents:
diff changeset
728 if (u->previous_nonadvancing_write)
kono
parents:
diff changeset
729 finish_last_advance_record (u);
kono
parents:
diff changeset
730
kono
parents:
diff changeset
731 rc = (u->s == NULL) ? 0 : sclose (u->s) == -1;
kono
parents:
diff changeset
732
kono
parents:
diff changeset
733 u->closed = 1;
kono
parents:
diff changeset
734 if (!locked)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
735 LOCK (&unit_lock);
111
kono
parents:
diff changeset
736
kono
parents:
diff changeset
737 for (i = 0; i < CACHE_SIZE; i++)
kono
parents:
diff changeset
738 if (unit_cache[i] == u)
kono
parents:
diff changeset
739 unit_cache[i] = NULL;
kono
parents:
diff changeset
740
kono
parents:
diff changeset
741 delete_unit (u);
kono
parents:
diff changeset
742
kono
parents:
diff changeset
743 free (u->filename);
kono
parents:
diff changeset
744 u->filename = NULL;
kono
parents:
diff changeset
745
kono
parents:
diff changeset
746 free_format_hash_table (u);
kono
parents:
diff changeset
747 fbuf_destroy (u);
kono
parents:
diff changeset
748
kono
parents:
diff changeset
749 if (u->unit_number <= NEWUNIT_START)
kono
parents:
diff changeset
750 newunit_free (u->unit_number);
kono
parents:
diff changeset
751
kono
parents:
diff changeset
752 if (!locked)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
753 UNLOCK (&u->lock);
111
kono
parents:
diff changeset
754
kono
parents:
diff changeset
755 /* If there are any threads waiting in find_unit for this unit,
kono
parents:
diff changeset
756 avoid freeing the memory, the last such thread will free it
kono
parents:
diff changeset
757 instead. */
kono
parents:
diff changeset
758 if (u->waiting == 0)
kono
parents:
diff changeset
759 destroy_unit_mutex (u);
kono
parents:
diff changeset
760
kono
parents:
diff changeset
761 if (!locked)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
762 UNLOCK (&unit_lock);
111
kono
parents:
diff changeset
763
kono
parents:
diff changeset
764 return rc;
kono
parents:
diff changeset
765 }
kono
parents:
diff changeset
766
kono
parents:
diff changeset
767 void
kono
parents:
diff changeset
768 unlock_unit (gfc_unit *u)
kono
parents:
diff changeset
769 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
770 NOTE ("unlock_unit = %d", u->unit_number);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
771 UNLOCK (&u->lock);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
772 NOTE ("unlock_unit done");
111
kono
parents:
diff changeset
773 }
kono
parents:
diff changeset
774
kono
parents:
diff changeset
775 /* close_unit()-- Close a unit. The stream is closed, and any memory
kono
parents:
diff changeset
776 associated with the stream is freed. Returns nonzero on I/O error.
kono
parents:
diff changeset
777 Should be called with the u->lock locked. */
kono
parents:
diff changeset
778
kono
parents:
diff changeset
779 int
kono
parents:
diff changeset
780 close_unit (gfc_unit *u)
kono
parents:
diff changeset
781 {
kono
parents:
diff changeset
782 return close_unit_1 (u, 0);
kono
parents:
diff changeset
783 }
kono
parents:
diff changeset
784
kono
parents:
diff changeset
785
kono
parents:
diff changeset
786 /* close_units()-- Delete units on completion. We just keep deleting
kono
parents:
diff changeset
787 the root of the treap until there is nothing left.
kono
parents:
diff changeset
788 Not sure what to do with locking here. Some other thread might be
kono
parents:
diff changeset
789 holding some unit's lock and perhaps hold it indefinitely
kono
parents:
diff changeset
790 (e.g. waiting for input from some pipe) and close_units shouldn't
kono
parents:
diff changeset
791 delay the program too much. */
kono
parents:
diff changeset
792
kono
parents:
diff changeset
793 void
kono
parents:
diff changeset
794 close_units (void)
kono
parents:
diff changeset
795 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
796 LOCK (&unit_lock);
111
kono
parents:
diff changeset
797 while (unit_root != NULL)
kono
parents:
diff changeset
798 close_unit_1 (unit_root, 1);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
799 UNLOCK (&unit_lock);
111
kono
parents:
diff changeset
800
kono
parents:
diff changeset
801 free (newunits);
kono
parents:
diff changeset
802
kono
parents:
diff changeset
803 #ifdef HAVE_FREELOCALE
kono
parents:
diff changeset
804 freelocale (c_locale);
kono
parents:
diff changeset
805 #endif
kono
parents:
diff changeset
806 }
kono
parents:
diff changeset
807
kono
parents:
diff changeset
808
kono
parents:
diff changeset
809 /* High level interface to truncate a file, i.e. flush format buffers,
kono
parents:
diff changeset
810 and generate an error or set some flags. Just like POSIX
kono
parents:
diff changeset
811 ftruncate, returns 0 on success, -1 on failure. */
kono
parents:
diff changeset
812
kono
parents:
diff changeset
813 int
kono
parents:
diff changeset
814 unit_truncate (gfc_unit *u, gfc_offset pos, st_parameter_common *common)
kono
parents:
diff changeset
815 {
kono
parents:
diff changeset
816 int ret;
kono
parents:
diff changeset
817
kono
parents:
diff changeset
818 /* Make sure format buffer is flushed. */
kono
parents:
diff changeset
819 if (u->flags.form == FORM_FORMATTED)
kono
parents:
diff changeset
820 {
kono
parents:
diff changeset
821 if (u->mode == READING)
kono
parents:
diff changeset
822 pos += fbuf_reset (u);
kono
parents:
diff changeset
823 else
kono
parents:
diff changeset
824 fbuf_flush (u, u->mode);
kono
parents:
diff changeset
825 }
kono
parents:
diff changeset
826
kono
parents:
diff changeset
827 /* struncate() should flush the stream buffer if necessary, so don't
kono
parents:
diff changeset
828 bother calling sflush() here. */
kono
parents:
diff changeset
829 ret = struncate (u->s, pos);
kono
parents:
diff changeset
830
kono
parents:
diff changeset
831 if (ret != 0)
kono
parents:
diff changeset
832 generate_error (common, LIBERROR_OS, NULL);
kono
parents:
diff changeset
833 else
kono
parents:
diff changeset
834 {
kono
parents:
diff changeset
835 u->endfile = AT_ENDFILE;
kono
parents:
diff changeset
836 u->flags.position = POSITION_APPEND;
kono
parents:
diff changeset
837 }
kono
parents:
diff changeset
838
kono
parents:
diff changeset
839 return ret;
kono
parents:
diff changeset
840 }
kono
parents:
diff changeset
841
kono
parents:
diff changeset
842
kono
parents:
diff changeset
843 /* filename_from_unit()-- If the unit_number exists, return a pointer to the
kono
parents:
diff changeset
844 name of the associated file, otherwise return the empty string. The caller
kono
parents:
diff changeset
845 must free memory allocated for the filename string. */
kono
parents:
diff changeset
846
kono
parents:
diff changeset
847 char *
kono
parents:
diff changeset
848 filename_from_unit (int n)
kono
parents:
diff changeset
849 {
kono
parents:
diff changeset
850 gfc_unit *u;
kono
parents:
diff changeset
851 int c;
kono
parents:
diff changeset
852
kono
parents:
diff changeset
853 /* Find the unit. */
kono
parents:
diff changeset
854 u = unit_root;
kono
parents:
diff changeset
855 while (u != NULL)
kono
parents:
diff changeset
856 {
kono
parents:
diff changeset
857 c = compare (n, u->unit_number);
kono
parents:
diff changeset
858 if (c < 0)
kono
parents:
diff changeset
859 u = u->left;
kono
parents:
diff changeset
860 if (c > 0)
kono
parents:
diff changeset
861 u = u->right;
kono
parents:
diff changeset
862 if (c == 0)
kono
parents:
diff changeset
863 break;
kono
parents:
diff changeset
864 }
kono
parents:
diff changeset
865
kono
parents:
diff changeset
866 /* Get the filename. */
kono
parents:
diff changeset
867 if (u != NULL && u->filename != NULL)
kono
parents:
diff changeset
868 return strdup (u->filename);
kono
parents:
diff changeset
869 else
kono
parents:
diff changeset
870 return (char *) NULL;
kono
parents:
diff changeset
871 }
kono
parents:
diff changeset
872
kono
parents:
diff changeset
873 void
kono
parents:
diff changeset
874 finish_last_advance_record (gfc_unit *u)
kono
parents:
diff changeset
875 {
kono
parents:
diff changeset
876
kono
parents:
diff changeset
877 if (u->saved_pos > 0)
kono
parents:
diff changeset
878 fbuf_seek (u, u->saved_pos, SEEK_CUR);
kono
parents:
diff changeset
879
kono
parents:
diff changeset
880 if (!(u->unit_number == options.stdout_unit
kono
parents:
diff changeset
881 || u->unit_number == options.stderr_unit))
kono
parents:
diff changeset
882 {
kono
parents:
diff changeset
883 #ifdef HAVE_CRLF
kono
parents:
diff changeset
884 const int len = 2;
kono
parents:
diff changeset
885 #else
kono
parents:
diff changeset
886 const int len = 1;
kono
parents:
diff changeset
887 #endif
kono
parents:
diff changeset
888 char *p = fbuf_alloc (u, len);
kono
parents:
diff changeset
889 if (!p)
kono
parents:
diff changeset
890 os_error ("Completing record after ADVANCE_NO failed");
kono
parents:
diff changeset
891 #ifdef HAVE_CRLF
kono
parents:
diff changeset
892 *(p++) = '\r';
kono
parents:
diff changeset
893 #endif
kono
parents:
diff changeset
894 *p = '\n';
kono
parents:
diff changeset
895 }
kono
parents:
diff changeset
896
kono
parents:
diff changeset
897 fbuf_flush (u, u->mode);
kono
parents:
diff changeset
898 }
kono
parents:
diff changeset
899
kono
parents:
diff changeset
900
kono
parents:
diff changeset
901 /* Assign a negative number for NEWUNIT in OPEN statements or for
kono
parents:
diff changeset
902 internal units. */
kono
parents:
diff changeset
903 int
kono
parents:
diff changeset
904 newunit_alloc (void)
kono
parents:
diff changeset
905 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
906 LOCK (&unit_lock);
111
kono
parents:
diff changeset
907 if (!newunits)
kono
parents:
diff changeset
908 {
kono
parents:
diff changeset
909 newunits = xcalloc (16, 1);
kono
parents:
diff changeset
910 newunit_size = 16;
kono
parents:
diff changeset
911 }
kono
parents:
diff changeset
912
kono
parents:
diff changeset
913 /* Search for the next available newunit. */
kono
parents:
diff changeset
914 for (int ii = newunit_lwi; ii < newunit_size; ii++)
kono
parents:
diff changeset
915 {
kono
parents:
diff changeset
916 if (!newunits[ii])
kono
parents:
diff changeset
917 {
kono
parents:
diff changeset
918 newunits[ii] = true;
kono
parents:
diff changeset
919 newunit_lwi = ii + 1;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
920 UNLOCK (&unit_lock);
111
kono
parents:
diff changeset
921 return -ii + NEWUNIT_START;
kono
parents:
diff changeset
922 }
kono
parents:
diff changeset
923 }
kono
parents:
diff changeset
924
kono
parents:
diff changeset
925 /* Search failed, bump size of array and allocate the first
kono
parents:
diff changeset
926 available unit. */
kono
parents:
diff changeset
927 int old_size = newunit_size;
kono
parents:
diff changeset
928 newunit_size *= 2;
kono
parents:
diff changeset
929 newunits = xrealloc (newunits, newunit_size);
kono
parents:
diff changeset
930 memset (newunits + old_size, 0, old_size);
kono
parents:
diff changeset
931 newunits[old_size] = true;
kono
parents:
diff changeset
932 newunit_lwi = old_size + 1;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
933 UNLOCK (&unit_lock);
111
kono
parents:
diff changeset
934 return -old_size + NEWUNIT_START;
kono
parents:
diff changeset
935 }
kono
parents:
diff changeset
936
kono
parents:
diff changeset
937
kono
parents:
diff changeset
938 /* Free a previously allocated newunit= unit number. unit_lock must
kono
parents:
diff changeset
939 be held when calling. */
kono
parents:
diff changeset
940
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
941 void
111
kono
parents:
diff changeset
942 newunit_free (int unit)
kono
parents:
diff changeset
943 {
kono
parents:
diff changeset
944 int ind = -unit + NEWUNIT_START;
kono
parents:
diff changeset
945 assert(ind >= 0 && ind < newunit_size);
kono
parents:
diff changeset
946 newunits[ind] = false;
kono
parents:
diff changeset
947 if (ind < newunit_lwi)
kono
parents:
diff changeset
948 newunit_lwi = ind;
kono
parents:
diff changeset
949 }