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