2017-03-14 Richard Biener <rguenther@suse.de>
[official-gcc.git] / libgfortran / io / unit.c
blobb733b939b69edf90274f120971b0bd465fccc4a1
1 /* Copyright (C) 2002-2017 Free Software Foundation, Inc.
2 Contributed by Andy Vaught
3 F2003 I/O support contributed by Jerry DeLisle
5 This file is part of the GNU Fortran runtime library (libgfortran).
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.
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.
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.
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/>. */
26 #include "io.h"
27 #include "fbuf.h"
28 #include "format.h"
29 #include "unix.h"
30 #include <string.h>
31 #include <assert.h>
34 /* IO locking rules:
35 UNIT_LOCK is a master lock, protecting UNIT_ROOT tree and UNIT_CACHE.
36 Concurrent use of different units should be supported, so
37 each unit has its own lock, LOCK.
38 Open should be atomic with its reopening of units and list_read.c
39 in several places needs find_unit another unit while holding stdin
40 unit's lock, so it must be possible to acquire UNIT_LOCK while holding
41 some unit's lock. Therefore to avoid deadlocks, it is forbidden
42 to acquire unit's private locks while holding UNIT_LOCK, except
43 for freshly created units (where no other thread can get at their
44 address yet) or when using just trylock rather than lock operation.
45 In addition to unit's private lock each unit has a WAITERS counter
46 and CLOSED flag. WAITERS counter must be either only
47 atomically incremented/decremented in all places (if atomic builtins
48 are supported), or protected by UNIT_LOCK in all places (otherwise).
49 CLOSED flag must be always protected by unit's LOCK.
50 After finding a unit in UNIT_CACHE or UNIT_ROOT with UNIT_LOCK held,
51 WAITERS must be incremented to avoid concurrent close from freeing
52 the unit between unlocking UNIT_LOCK and acquiring unit's LOCK.
53 Unit freeing is always done under UNIT_LOCK. If close_unit sees any
54 WAITERS, it doesn't free the unit but instead sets the CLOSED flag
55 and the thread that decrements WAITERS to zero while CLOSED flag is
56 set is responsible for freeing it (while holding UNIT_LOCK).
57 flush_all_units operation is iterating over the unit tree with
58 increasing UNIT_NUMBER while holding UNIT_LOCK and attempting to
59 flush each unit (and therefore needs the unit's LOCK held as well).
60 To avoid deadlocks, it just trylocks the LOCK and if unsuccessful,
61 remembers the current unit's UNIT_NUMBER, unlocks UNIT_LOCK, acquires
62 unit's LOCK and after flushing reacquires UNIT_LOCK and restarts with
63 the smallest UNIT_NUMBER above the last one flushed.
65 If find_unit/find_or_create_unit/find_file/get_unit routines return
66 non-NULL, the returned unit has its private lock locked and when the
67 caller is done with it, it must call either unlock_unit or close_unit
68 on it. unlock_unit or close_unit must be always called only with the
69 private lock held. */
73 /* Table of allocated newunit values. A simple solution would be to
74 map OS file descriptors (fd's) to unit numbers, e.g. with newunit =
75 -fd - 2, however that doesn't work since Fortran allows an existing
76 unit number to be reassociated with a new file. Thus the simple
77 approach may lead to a situation where we'd try to assign a
78 (negative) unit number which already exists. Hence we must keep
79 track of allocated newunit values ourselves. This is the purpose of
80 the newunits array. The indices map to newunit values as newunit =
81 -index + NEWUNIT_FIRST. E.g. newunits[0] having the value true
82 means that a unit with number NEWUNIT_FIRST exists. Similar to
83 POSIX file descriptors, we always allocate the lowest (in absolute
84 value) available unit number.
86 static bool *newunits;
87 static int newunit_size; /* Total number of elements in the newunits array. */
88 /* Low water indicator for the newunits array. Below the LWI all the
89 units are allocated, above and equal to the LWI there may be both
90 allocated and free units. */
91 static int newunit_lwi;
92 static void newunit_free (int);
94 /* Unit numbers assigned with NEWUNIT start from here. */
95 #define NEWUNIT_START -10
98 #define NEWUNIT_STACK_SIZE 16
100 /* A stack to save previously used newunit-assigned unit numbers to
101 allow them to be reused without reallocating the gfc_unit structure
102 which is still in the treap. */
103 static gfc_saved_unit newunit_stack[NEWUNIT_STACK_SIZE];
104 static int newunit_tos = 0; /* Index to Top of Stack. */
107 #define CACHE_SIZE 3
108 static gfc_unit *unit_cache[CACHE_SIZE];
109 gfc_offset max_offset;
110 gfc_unit *unit_root;
111 #ifdef __GTHREAD_MUTEX_INIT
112 __gthread_mutex_t unit_lock = __GTHREAD_MUTEX_INIT;
113 #else
114 __gthread_mutex_t unit_lock;
115 #endif
117 /* We use these filenames for error reporting. */
119 static char stdin_name[] = "stdin";
120 static char stdout_name[] = "stdout";
121 static char stderr_name[] = "stderr";
124 #ifdef HAVE_NEWLOCALE
125 locale_t c_locale;
126 #else
127 /* If we don't have POSIX 2008 per-thread locales, we need to use the
128 traditional setlocale(). To prevent multiple concurrent threads
129 doing formatted I/O from messing up the locale, we need to store a
130 global old_locale, and a counter keeping track of how many threads
131 are currently doing formatted I/O. The first thread saves the old
132 locale, and the last one restores it. */
133 char *old_locale;
134 int old_locale_ctr;
135 #ifdef __GTHREAD_MUTEX_INIT
136 __gthread_mutex_t old_locale_lock = __GTHREAD_MUTEX_INIT;
137 #else
138 __gthread_mutex_t old_locale_lock;
139 #endif
140 #endif
143 /* This implementation is based on Stefan Nilsson's article in the
144 * July 1997 Doctor Dobb's Journal, "Treaps in Java". */
146 /* pseudo_random()-- Simple linear congruential pseudorandom number
147 * generator. The period of this generator is 44071, which is plenty
148 * for our purposes. */
150 static int
151 pseudo_random (void)
153 static int x0 = 5341;
155 x0 = (22611 * x0 + 10) % 44071;
156 return x0;
160 /* rotate_left()-- Rotate the treap left */
162 static gfc_unit *
163 rotate_left (gfc_unit * t)
165 gfc_unit *temp;
167 temp = t->right;
168 t->right = t->right->left;
169 temp->left = t;
171 return temp;
175 /* rotate_right()-- Rotate the treap right */
177 static gfc_unit *
178 rotate_right (gfc_unit * t)
180 gfc_unit *temp;
182 temp = t->left;
183 t->left = t->left->right;
184 temp->right = t;
186 return temp;
190 static int
191 compare (int a, int b)
193 if (a < b)
194 return -1;
195 if (a > b)
196 return 1;
198 return 0;
202 /* insert()-- Recursive insertion function. Returns the updated treap. */
204 static gfc_unit *
205 insert (gfc_unit *new, gfc_unit *t)
207 int c;
209 if (t == NULL)
210 return new;
212 c = compare (new->unit_number, t->unit_number);
214 if (c < 0)
216 t->left = insert (new, t->left);
217 if (t->priority < t->left->priority)
218 t = rotate_right (t);
221 if (c > 0)
223 t->right = insert (new, t->right);
224 if (t->priority < t->right->priority)
225 t = rotate_left (t);
228 if (c == 0)
229 internal_error (NULL, "insert(): Duplicate key found!");
231 return t;
235 /* insert_unit()-- Create a new node, insert it into the treap. */
237 static gfc_unit *
238 insert_unit (int n)
240 gfc_unit *u = xcalloc (1, sizeof (gfc_unit));
241 u->unit_number = n;
242 #ifdef __GTHREAD_MUTEX_INIT
244 __gthread_mutex_t tmp = __GTHREAD_MUTEX_INIT;
245 u->lock = tmp;
247 #else
248 __GTHREAD_MUTEX_INIT_FUNCTION (&u->lock);
249 #endif
250 __gthread_mutex_lock (&u->lock);
251 u->priority = pseudo_random ();
252 unit_root = insert (u, unit_root);
253 return u;
257 /* destroy_unit_mutex()-- Destroy the mutex and free memory of unit. */
259 static void
260 destroy_unit_mutex (gfc_unit * u)
262 __gthread_mutex_destroy (&u->lock);
263 free (u);
267 static gfc_unit *
268 delete_root (gfc_unit * t)
270 gfc_unit *temp;
272 if (t->left == NULL)
273 return t->right;
274 if (t->right == NULL)
275 return t->left;
277 if (t->left->priority > t->right->priority)
279 temp = rotate_right (t);
280 temp->right = delete_root (t);
282 else
284 temp = rotate_left (t);
285 temp->left = delete_root (t);
288 return temp;
292 /* delete_treap()-- Delete an element from a tree. The 'old' value
293 * does not necessarily have to point to the element to be deleted, it
294 * must just point to a treap structure with the key to be deleted.
295 * Returns the new root node of the tree. */
297 static gfc_unit *
298 delete_treap (gfc_unit * old, gfc_unit * t)
300 int c;
302 if (t == NULL)
303 return NULL;
305 c = compare (old->unit_number, t->unit_number);
307 if (c < 0)
308 t->left = delete_treap (old, t->left);
309 if (c > 0)
310 t->right = delete_treap (old, t->right);
311 if (c == 0)
312 t = delete_root (t);
314 return t;
318 /* delete_unit()-- Delete a unit from a tree */
320 static void
321 delete_unit (gfc_unit * old)
323 unit_root = delete_treap (old, unit_root);
327 /* get_gfc_unit()-- Given an integer, return a pointer to the unit
328 * structure. Returns NULL if the unit does not exist,
329 * otherwise returns a locked unit. */
331 static gfc_unit *
332 get_gfc_unit (int n, int do_create)
334 gfc_unit *p;
335 int c, created = 0;
337 __gthread_mutex_lock (&unit_lock);
338 retry:
339 for (c = 0; c < CACHE_SIZE; c++)
340 if (unit_cache[c] != NULL && unit_cache[c]->unit_number == n)
342 p = unit_cache[c];
343 goto found;
346 p = unit_root;
347 while (p != NULL)
349 c = compare (n, p->unit_number);
350 if (c < 0)
351 p = p->left;
352 if (c > 0)
353 p = p->right;
354 if (c == 0)
355 break;
358 if (p == NULL && do_create)
360 p = insert_unit (n);
361 created = 1;
364 if (p != NULL)
366 for (c = 0; c < CACHE_SIZE - 1; c++)
367 unit_cache[c] = unit_cache[c + 1];
369 unit_cache[CACHE_SIZE - 1] = p;
372 if (created)
374 /* Newly created units have their lock held already
375 from insert_unit. Just unlock UNIT_LOCK and return. */
376 __gthread_mutex_unlock (&unit_lock);
377 return p;
380 found:
381 if (p != NULL && (p->child_dtio == 0))
383 /* Fast path. */
384 if (! __gthread_mutex_trylock (&p->lock))
386 /* assert (p->closed == 0); */
387 __gthread_mutex_unlock (&unit_lock);
388 return p;
391 inc_waiting_locked (p);
395 __gthread_mutex_unlock (&unit_lock);
397 if (p != NULL && (p->child_dtio == 0))
399 __gthread_mutex_lock (&p->lock);
400 if (p->closed)
402 __gthread_mutex_lock (&unit_lock);
403 __gthread_mutex_unlock (&p->lock);
404 if (predec_waiting_locked (p) == 0)
405 destroy_unit_mutex (p);
406 goto retry;
409 dec_waiting_unlocked (p);
411 return p;
415 gfc_unit *
416 find_unit (int n)
418 return get_gfc_unit (n, 0);
422 gfc_unit *
423 find_or_create_unit (int n)
425 return get_gfc_unit (n, 1);
429 /* Helper function to check rank, stride, format string, and namelist.
430 This is used for optimization. You can't trim out blanks or shorten
431 the string if trailing spaces are significant. */
432 static bool
433 is_trim_ok (st_parameter_dt *dtp)
435 /* Check rank and stride. */
436 if (dtp->internal_unit_desc)
437 return false;
438 /* Format strings can not have 'BZ' or '/'. */
439 if (dtp->common.flags & IOPARM_DT_HAS_FORMAT)
441 char *p = dtp->format;
442 off_t i;
443 if (dtp->common.flags & IOPARM_DT_HAS_BLANK)
444 return false;
445 for (i = 0; i < dtp->format_len; i++)
447 if (p[i] == '/') return false;
448 if (p[i] == 'b' || p[i] == 'B')
449 if (p[i+1] == 'z' || p[i+1] == 'Z')
450 return false;
453 if (dtp->u.p.ionml) /* A namelist. */
454 return false;
455 return true;
459 gfc_unit *
460 set_internal_unit (st_parameter_dt *dtp, gfc_unit *iunit, int kind)
462 gfc_offset start_record = 0;
464 iunit->unit_number = dtp->common.unit;
465 iunit->recl = dtp->internal_unit_len;
466 iunit->internal_unit = dtp->internal_unit;
467 iunit->internal_unit_len = dtp->internal_unit_len;
468 iunit->internal_unit_kind = kind;
470 /* As an optimization, adjust the unit record length to not
471 include trailing blanks. This will not work under certain conditions
472 where trailing blanks have significance. */
473 if (dtp->u.p.mode == READING && is_trim_ok (dtp))
475 int len;
476 if (kind == 1)
477 len = string_len_trim (iunit->internal_unit_len,
478 iunit->internal_unit);
479 else
480 len = string_len_trim_char4 (iunit->internal_unit_len,
481 (const gfc_char4_t*) iunit->internal_unit);
482 iunit->internal_unit_len = len;
483 iunit->recl = iunit->internal_unit_len;
486 /* Set up the looping specification from the array descriptor, if any. */
488 if (is_array_io (dtp))
490 iunit->rank = GFC_DESCRIPTOR_RANK (dtp->internal_unit_desc);
491 iunit->ls = (array_loop_spec *)
492 xmallocarray (iunit->rank, sizeof (array_loop_spec));
493 iunit->internal_unit_len *=
494 init_loop_spec (dtp->internal_unit_desc, iunit->ls, &start_record);
496 start_record *= iunit->recl;
499 /* Set initial values for unit parameters. */
500 if (kind == 4)
501 iunit->s = open_internal4 (iunit->internal_unit - start_record,
502 iunit->internal_unit_len, -start_record);
503 else
504 iunit->s = open_internal (iunit->internal_unit - start_record,
505 iunit->internal_unit_len, -start_record);
507 iunit->bytes_left = iunit->recl;
508 iunit->last_record=0;
509 iunit->maxrec=0;
510 iunit->current_record=0;
511 iunit->read_bad = 0;
512 iunit->endfile = NO_ENDFILE;
514 /* Set flags for the internal unit. */
516 iunit->flags.access = ACCESS_SEQUENTIAL;
517 iunit->flags.action = ACTION_READWRITE;
518 iunit->flags.blank = BLANK_NULL;
519 iunit->flags.form = FORM_FORMATTED;
520 iunit->flags.pad = PAD_YES;
521 iunit->flags.status = STATUS_UNSPECIFIED;
522 iunit->flags.sign = SIGN_UNSPECIFIED;
523 iunit->flags.decimal = DECIMAL_POINT;
524 iunit->flags.delim = DELIM_UNSPECIFIED;
525 iunit->flags.encoding = ENCODING_DEFAULT;
526 iunit->flags.async = ASYNC_NO;
527 iunit->flags.round = ROUND_UNSPECIFIED;
529 /* Initialize the data transfer parameters. */
531 dtp->u.p.advance_status = ADVANCE_YES;
532 dtp->u.p.seen_dollar = 0;
533 dtp->u.p.skips = 0;
534 dtp->u.p.pending_spaces = 0;
535 dtp->u.p.max_pos = 0;
536 dtp->u.p.at_eof = 0;
537 return iunit;
541 /* stash_internal_unit()-- Push the internal unit number onto the
542 avaialble stack. */
543 void
544 stash_internal_unit (st_parameter_dt *dtp)
546 __gthread_mutex_lock (&unit_lock);
547 newunit_tos++;
548 if (newunit_tos >= NEWUNIT_STACK_SIZE)
549 internal_error (&dtp->common, "stash_internal_unit(): Stack Size Exceeded");
550 newunit_stack[newunit_tos].unit_number = dtp->common.unit;
551 newunit_stack[newunit_tos].unit = dtp->u.p.current_unit;
552 __gthread_mutex_unlock (&unit_lock);
557 /* get_unit()-- Returns the unit structure associated with the integer
558 unit or the internal file. */
560 gfc_unit *
561 get_unit (st_parameter_dt *dtp, int do_create)
563 gfc_unit * unit;
565 if ((dtp->common.flags & IOPARM_DT_HAS_INTERNAL_UNIT) != 0)
567 int kind;
568 if (dtp->common.unit == GFC_INTERNAL_UNIT)
569 kind = 1;
570 else if (dtp->common.unit == GFC_INTERNAL_UNIT4)
571 kind = 4;
572 else
573 internal_error (&dtp->common, "get_unit(): Bad internal unit KIND");
575 if ((dtp->common.flags & IOPARM_DT_HAS_UDTIO) != 0)
577 dtp->u.p.unit_is_internal = 1;
578 dtp->common.unit = newunit_alloc ();
579 unit = get_gfc_unit (dtp->common.unit, do_create);
580 set_internal_unit (dtp, unit, kind);
581 fbuf_init (unit, 128);
582 return unit;
584 else
586 if (newunit_tos)
588 dtp->common.unit = newunit_stack[newunit_tos].unit_number;
589 unit = newunit_stack[newunit_tos--].unit;
590 unit->fbuf->act = unit->fbuf->pos = 0;
592 else
594 dtp->common.unit = newunit_alloc ();
595 unit = xcalloc (1, sizeof (gfc_unit));
596 fbuf_init (unit, 128);
598 set_internal_unit (dtp, unit, kind);
599 return unit;
603 /* If an internal unit number is passed from the parent to the child
604 it should have been stashed on the newunit_stack ready to be used.
605 Check for it now and return the internal unit if found. */
606 if (newunit_tos && (dtp->common.unit <= NEWUNIT_START)
607 && (dtp->common.unit == newunit_stack[newunit_tos].unit_number))
609 unit = newunit_stack[newunit_tos--].unit;
610 return unit;
613 /* Has to be an external unit. */
614 dtp->u.p.unit_is_internal = 0;
615 dtp->internal_unit = NULL;
616 dtp->internal_unit_desc = NULL;
618 /* For an external unit with unit number < 0 creating it on the fly
619 is not allowed, such units must be created with
620 OPEN(NEWUNIT=...). */
621 if (dtp->common.unit < 0)
622 return get_gfc_unit (dtp->common.unit, 0);
624 return get_gfc_unit (dtp->common.unit, do_create);
628 /*************************/
629 /* Initialize everything. */
631 void
632 init_units (void)
634 gfc_unit *u;
635 unsigned int i;
637 #ifdef HAVE_NEWLOCALE
638 c_locale = newlocale (0, "C", 0);
639 #else
640 #ifndef __GTHREAD_MUTEX_INIT
641 __GTHREAD_MUTEX_INIT_FUNCTION (&old_locale_lock);
642 #endif
643 #endif
645 #ifndef __GTHREAD_MUTEX_INIT
646 __GTHREAD_MUTEX_INIT_FUNCTION (&unit_lock);
647 #endif
649 if (options.stdin_unit >= 0)
650 { /* STDIN */
651 u = insert_unit (options.stdin_unit);
652 u->s = input_stream ();
654 u->flags.action = ACTION_READ;
656 u->flags.access = ACCESS_SEQUENTIAL;
657 u->flags.form = FORM_FORMATTED;
658 u->flags.status = STATUS_OLD;
659 u->flags.blank = BLANK_NULL;
660 u->flags.pad = PAD_YES;
661 u->flags.position = POSITION_ASIS;
662 u->flags.sign = SIGN_UNSPECIFIED;
663 u->flags.decimal = DECIMAL_POINT;
664 u->flags.delim = DELIM_UNSPECIFIED;
665 u->flags.encoding = ENCODING_DEFAULT;
666 u->flags.async = ASYNC_NO;
667 u->flags.round = ROUND_UNSPECIFIED;
668 u->flags.share = SHARE_UNSPECIFIED;
669 u->flags.cc = CC_LIST;
671 u->recl = options.default_recl;
672 u->endfile = NO_ENDFILE;
674 u->filename = strdup (stdin_name);
676 fbuf_init (u, 0);
678 __gthread_mutex_unlock (&u->lock);
681 if (options.stdout_unit >= 0)
682 { /* STDOUT */
683 u = insert_unit (options.stdout_unit);
684 u->s = output_stream ();
686 u->flags.action = ACTION_WRITE;
688 u->flags.access = ACCESS_SEQUENTIAL;
689 u->flags.form = FORM_FORMATTED;
690 u->flags.status = STATUS_OLD;
691 u->flags.blank = BLANK_NULL;
692 u->flags.position = POSITION_ASIS;
693 u->flags.sign = SIGN_UNSPECIFIED;
694 u->flags.decimal = DECIMAL_POINT;
695 u->flags.delim = DELIM_UNSPECIFIED;
696 u->flags.encoding = ENCODING_DEFAULT;
697 u->flags.async = ASYNC_NO;
698 u->flags.round = ROUND_UNSPECIFIED;
699 u->flags.share = SHARE_UNSPECIFIED;
700 u->flags.cc = CC_LIST;
702 u->recl = options.default_recl;
703 u->endfile = AT_ENDFILE;
705 u->filename = strdup (stdout_name);
707 fbuf_init (u, 0);
709 __gthread_mutex_unlock (&u->lock);
712 if (options.stderr_unit >= 0)
713 { /* STDERR */
714 u = insert_unit (options.stderr_unit);
715 u->s = error_stream ();
717 u->flags.action = ACTION_WRITE;
719 u->flags.access = ACCESS_SEQUENTIAL;
720 u->flags.form = FORM_FORMATTED;
721 u->flags.status = STATUS_OLD;
722 u->flags.blank = BLANK_NULL;
723 u->flags.position = POSITION_ASIS;
724 u->flags.sign = SIGN_UNSPECIFIED;
725 u->flags.decimal = DECIMAL_POINT;
726 u->flags.encoding = ENCODING_DEFAULT;
727 u->flags.async = ASYNC_NO;
728 u->flags.round = ROUND_UNSPECIFIED;
729 u->flags.share = SHARE_UNSPECIFIED;
730 u->flags.cc = CC_LIST;
732 u->recl = options.default_recl;
733 u->endfile = AT_ENDFILE;
735 u->filename = strdup (stderr_name);
737 fbuf_init (u, 256); /* 256 bytes should be enough, probably not doing
738 any kind of exotic formatting to stderr. */
740 __gthread_mutex_unlock (&u->lock);
743 /* Calculate the maximum file offset in a portable manner.
744 max will be the largest signed number for the type gfc_offset.
745 set a 1 in the LSB and keep a running sum, stopping at MSB-1 bit. */
746 max_offset = 0;
747 for (i = 0; i < sizeof (max_offset) * 8 - 1; i++)
748 max_offset = max_offset + ((gfc_offset) 1 << i);
750 /* Initialize the newunit stack. */
751 memset (newunit_stack, 0, NEWUNIT_STACK_SIZE * sizeof(gfc_saved_unit));
752 newunit_tos = 0;
756 static int
757 close_unit_1 (gfc_unit *u, int locked)
759 int i, rc;
761 /* If there are previously written bytes from a write with ADVANCE="no"
762 Reposition the buffer before closing. */
763 if (u->previous_nonadvancing_write)
764 finish_last_advance_record (u);
766 rc = (u->s == NULL) ? 0 : sclose (u->s) == -1;
768 u->closed = 1;
769 if (!locked)
770 __gthread_mutex_lock (&unit_lock);
772 for (i = 0; i < CACHE_SIZE; i++)
773 if (unit_cache[i] == u)
774 unit_cache[i] = NULL;
776 delete_unit (u);
778 free (u->filename);
779 u->filename = NULL;
781 free_format_hash_table (u);
782 fbuf_destroy (u);
784 if (u->unit_number <= NEWUNIT_START)
785 newunit_free (u->unit_number);
787 if (!locked)
788 __gthread_mutex_unlock (&u->lock);
790 /* If there are any threads waiting in find_unit for this unit,
791 avoid freeing the memory, the last such thread will free it
792 instead. */
793 if (u->waiting == 0)
794 destroy_unit_mutex (u);
796 if (!locked)
797 __gthread_mutex_unlock (&unit_lock);
799 return rc;
802 void
803 unlock_unit (gfc_unit *u)
805 __gthread_mutex_unlock (&u->lock);
808 /* close_unit()-- Close a unit. The stream is closed, and any memory
809 associated with the stream is freed. Returns nonzero on I/O error.
810 Should be called with the u->lock locked. */
813 close_unit (gfc_unit *u)
815 return close_unit_1 (u, 0);
819 /* close_units()-- Delete units on completion. We just keep deleting
820 the root of the treap until there is nothing left.
821 Not sure what to do with locking here. Some other thread might be
822 holding some unit's lock and perhaps hold it indefinitely
823 (e.g. waiting for input from some pipe) and close_units shouldn't
824 delay the program too much. */
826 void
827 close_units (void)
829 __gthread_mutex_lock (&unit_lock);
830 while (unit_root != NULL)
831 close_unit_1 (unit_root, 1);
832 __gthread_mutex_unlock (&unit_lock);
834 while (newunit_tos != 0)
835 if (newunit_stack[newunit_tos].unit)
837 fbuf_destroy (newunit_stack[newunit_tos].unit);
838 free (newunit_stack[newunit_tos].unit->s);
839 free (newunit_stack[newunit_tos--].unit);
842 free (newunits);
844 #ifdef HAVE_FREELOCALE
845 freelocale (c_locale);
846 #endif
850 /* High level interface to truncate a file, i.e. flush format buffers,
851 and generate an error or set some flags. Just like POSIX
852 ftruncate, returns 0 on success, -1 on failure. */
855 unit_truncate (gfc_unit * u, gfc_offset pos, st_parameter_common * common)
857 int ret;
859 /* Make sure format buffer is flushed. */
860 if (u->flags.form == FORM_FORMATTED)
862 if (u->mode == READING)
863 pos += fbuf_reset (u);
864 else
865 fbuf_flush (u, u->mode);
868 /* struncate() should flush the stream buffer if necessary, so don't
869 bother calling sflush() here. */
870 ret = struncate (u->s, pos);
872 if (ret != 0)
873 generate_error (common, LIBERROR_OS, NULL);
874 else
876 u->endfile = AT_ENDFILE;
877 u->flags.position = POSITION_APPEND;
880 return ret;
884 /* filename_from_unit()-- If the unit_number exists, return a pointer to the
885 name of the associated file, otherwise return the empty string. The caller
886 must free memory allocated for the filename string. */
888 char *
889 filename_from_unit (int n)
891 gfc_unit *u;
892 int c;
894 /* Find the unit. */
895 u = unit_root;
896 while (u != NULL)
898 c = compare (n, u->unit_number);
899 if (c < 0)
900 u = u->left;
901 if (c > 0)
902 u = u->right;
903 if (c == 0)
904 break;
907 /* Get the filename. */
908 if (u != NULL && u->filename != NULL)
909 return strdup (u->filename);
910 else
911 return (char *) NULL;
914 void
915 finish_last_advance_record (gfc_unit *u)
918 if (u->saved_pos > 0)
919 fbuf_seek (u, u->saved_pos, SEEK_CUR);
921 if (!(u->unit_number == options.stdout_unit
922 || u->unit_number == options.stderr_unit))
924 #ifdef HAVE_CRLF
925 const int len = 2;
926 #else
927 const int len = 1;
928 #endif
929 char *p = fbuf_alloc (u, len);
930 if (!p)
931 os_error ("Completing record after ADVANCE_NO failed");
932 #ifdef HAVE_CRLF
933 *(p++) = '\r';
934 #endif
935 *p = '\n';
938 fbuf_flush (u, u->mode);
942 /* Assign a negative number for NEWUNIT in OPEN statements or for
943 internal units. */
945 newunit_alloc (void)
947 __gthread_mutex_lock (&unit_lock);
948 if (!newunits)
950 newunits = xcalloc (16, 1);
951 newunit_size = 16;
954 /* Search for the next available newunit. */
955 for (int ii = newunit_lwi; ii < newunit_size; ii++)
957 if (!newunits[ii])
959 newunits[ii] = true;
960 newunit_lwi = ii + 1;
961 __gthread_mutex_unlock (&unit_lock);
962 return -ii + NEWUNIT_START;
966 /* Search failed, bump size of array and allocate the first
967 available unit. */
968 int old_size = newunit_size;
969 newunit_size *= 2;
970 newunits = xrealloc (newunits, newunit_size);
971 memset (newunits + old_size, 0, old_size);
972 newunits[old_size] = true;
973 newunit_lwi = old_size + 1;
974 __gthread_mutex_unlock (&unit_lock);
975 return -old_size + NEWUNIT_START;
979 /* Free a previously allocated newunit= unit number. unit_lock must
980 be held when calling. */
982 static void
983 newunit_free (int unit)
985 int ind = -unit + NEWUNIT_START;
986 assert(ind >= 0 && ind < newunit_size);
987 newunits[ind] = false;
988 if (ind < newunit_lwi)
989 newunit_lwi = ind;