Add support for ARMv8-R architecture
[official-gcc.git] / libgfortran / io / unit.c
blobef94294526a3628f5316d1e902a4b480c23ca986
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 __gthread_mutex_lock (&unit_lock);
587 if (newunit_tos)
589 dtp->common.unit = newunit_stack[newunit_tos].unit_number;
590 unit = newunit_stack[newunit_tos--].unit;
591 __gthread_mutex_unlock (&unit_lock);
592 unit->fbuf->act = unit->fbuf->pos = 0;
594 else
596 __gthread_mutex_unlock (&unit_lock);
597 dtp->common.unit = newunit_alloc ();
598 unit = xcalloc (1, sizeof (gfc_unit));
599 fbuf_init (unit, 128);
601 set_internal_unit (dtp, unit, kind);
602 return unit;
606 /* If an internal unit number is passed from the parent to the child
607 it should have been stashed on the newunit_stack ready to be used.
608 Check for it now and return the internal unit if found. */
609 __gthread_mutex_lock (&unit_lock);
610 if (newunit_tos && (dtp->common.unit <= NEWUNIT_START)
611 && (dtp->common.unit == newunit_stack[newunit_tos].unit_number))
613 unit = newunit_stack[newunit_tos--].unit;
614 __gthread_mutex_unlock (&unit_lock);
615 return unit;
617 __gthread_mutex_unlock (&unit_lock);
619 /* Has to be an external unit. */
620 dtp->u.p.unit_is_internal = 0;
621 dtp->internal_unit = NULL;
622 dtp->internal_unit_desc = NULL;
624 /* For an external unit with unit number < 0 creating it on the fly
625 is not allowed, such units must be created with
626 OPEN(NEWUNIT=...). */
627 if (dtp->common.unit < 0)
628 return get_gfc_unit (dtp->common.unit, 0);
630 return get_gfc_unit (dtp->common.unit, do_create);
634 /*************************/
635 /* Initialize everything. */
637 void
638 init_units (void)
640 gfc_unit *u;
641 unsigned int i;
643 #ifdef HAVE_NEWLOCALE
644 c_locale = newlocale (0, "C", 0);
645 #else
646 #ifndef __GTHREAD_MUTEX_INIT
647 __GTHREAD_MUTEX_INIT_FUNCTION (&old_locale_lock);
648 #endif
649 #endif
651 #ifndef __GTHREAD_MUTEX_INIT
652 __GTHREAD_MUTEX_INIT_FUNCTION (&unit_lock);
653 #endif
655 if (options.stdin_unit >= 0)
656 { /* STDIN */
657 u = insert_unit (options.stdin_unit);
658 u->s = input_stream ();
660 u->flags.action = ACTION_READ;
662 u->flags.access = ACCESS_SEQUENTIAL;
663 u->flags.form = FORM_FORMATTED;
664 u->flags.status = STATUS_OLD;
665 u->flags.blank = BLANK_NULL;
666 u->flags.pad = PAD_YES;
667 u->flags.position = POSITION_ASIS;
668 u->flags.sign = SIGN_UNSPECIFIED;
669 u->flags.decimal = DECIMAL_POINT;
670 u->flags.delim = DELIM_UNSPECIFIED;
671 u->flags.encoding = ENCODING_DEFAULT;
672 u->flags.async = ASYNC_NO;
673 u->flags.round = ROUND_UNSPECIFIED;
674 u->flags.share = SHARE_UNSPECIFIED;
675 u->flags.cc = CC_LIST;
677 u->recl = options.default_recl;
678 u->endfile = NO_ENDFILE;
680 u->filename = strdup (stdin_name);
682 fbuf_init (u, 0);
684 __gthread_mutex_unlock (&u->lock);
687 if (options.stdout_unit >= 0)
688 { /* STDOUT */
689 u = insert_unit (options.stdout_unit);
690 u->s = output_stream ();
692 u->flags.action = ACTION_WRITE;
694 u->flags.access = ACCESS_SEQUENTIAL;
695 u->flags.form = FORM_FORMATTED;
696 u->flags.status = STATUS_OLD;
697 u->flags.blank = BLANK_NULL;
698 u->flags.position = POSITION_ASIS;
699 u->flags.sign = SIGN_UNSPECIFIED;
700 u->flags.decimal = DECIMAL_POINT;
701 u->flags.delim = DELIM_UNSPECIFIED;
702 u->flags.encoding = ENCODING_DEFAULT;
703 u->flags.async = ASYNC_NO;
704 u->flags.round = ROUND_UNSPECIFIED;
705 u->flags.share = SHARE_UNSPECIFIED;
706 u->flags.cc = CC_LIST;
708 u->recl = options.default_recl;
709 u->endfile = AT_ENDFILE;
711 u->filename = strdup (stdout_name);
713 fbuf_init (u, 0);
715 __gthread_mutex_unlock (&u->lock);
718 if (options.stderr_unit >= 0)
719 { /* STDERR */
720 u = insert_unit (options.stderr_unit);
721 u->s = error_stream ();
723 u->flags.action = ACTION_WRITE;
725 u->flags.access = ACCESS_SEQUENTIAL;
726 u->flags.form = FORM_FORMATTED;
727 u->flags.status = STATUS_OLD;
728 u->flags.blank = BLANK_NULL;
729 u->flags.position = POSITION_ASIS;
730 u->flags.sign = SIGN_UNSPECIFIED;
731 u->flags.decimal = DECIMAL_POINT;
732 u->flags.encoding = ENCODING_DEFAULT;
733 u->flags.async = ASYNC_NO;
734 u->flags.round = ROUND_UNSPECIFIED;
735 u->flags.share = SHARE_UNSPECIFIED;
736 u->flags.cc = CC_LIST;
738 u->recl = options.default_recl;
739 u->endfile = AT_ENDFILE;
741 u->filename = strdup (stderr_name);
743 fbuf_init (u, 256); /* 256 bytes should be enough, probably not doing
744 any kind of exotic formatting to stderr. */
746 __gthread_mutex_unlock (&u->lock);
749 /* Calculate the maximum file offset in a portable manner.
750 max will be the largest signed number for the type gfc_offset.
751 set a 1 in the LSB and keep a running sum, stopping at MSB-1 bit. */
752 max_offset = 0;
753 for (i = 0; i < sizeof (max_offset) * 8 - 1; i++)
754 max_offset = max_offset + ((gfc_offset) 1 << i);
756 /* Initialize the newunit stack. */
757 memset (newunit_stack, 0, NEWUNIT_STACK_SIZE * sizeof(gfc_saved_unit));
758 newunit_tos = 0;
762 static int
763 close_unit_1 (gfc_unit *u, int locked)
765 int i, rc;
767 /* If there are previously written bytes from a write with ADVANCE="no"
768 Reposition the buffer before closing. */
769 if (u->previous_nonadvancing_write)
770 finish_last_advance_record (u);
772 rc = (u->s == NULL) ? 0 : sclose (u->s) == -1;
774 u->closed = 1;
775 if (!locked)
776 __gthread_mutex_lock (&unit_lock);
778 for (i = 0; i < CACHE_SIZE; i++)
779 if (unit_cache[i] == u)
780 unit_cache[i] = NULL;
782 delete_unit (u);
784 free (u->filename);
785 u->filename = NULL;
787 free_format_hash_table (u);
788 fbuf_destroy (u);
790 if (u->unit_number <= NEWUNIT_START)
791 newunit_free (u->unit_number);
793 if (!locked)
794 __gthread_mutex_unlock (&u->lock);
796 /* If there are any threads waiting in find_unit for this unit,
797 avoid freeing the memory, the last such thread will free it
798 instead. */
799 if (u->waiting == 0)
800 destroy_unit_mutex (u);
802 if (!locked)
803 __gthread_mutex_unlock (&unit_lock);
805 return rc;
808 void
809 unlock_unit (gfc_unit *u)
811 __gthread_mutex_unlock (&u->lock);
814 /* close_unit()-- Close a unit. The stream is closed, and any memory
815 associated with the stream is freed. Returns nonzero on I/O error.
816 Should be called with the u->lock locked. */
819 close_unit (gfc_unit *u)
821 return close_unit_1 (u, 0);
825 /* close_units()-- Delete units on completion. We just keep deleting
826 the root of the treap until there is nothing left.
827 Not sure what to do with locking here. Some other thread might be
828 holding some unit's lock and perhaps hold it indefinitely
829 (e.g. waiting for input from some pipe) and close_units shouldn't
830 delay the program too much. */
832 void
833 close_units (void)
835 __gthread_mutex_lock (&unit_lock);
836 while (unit_root != NULL)
837 close_unit_1 (unit_root, 1);
838 __gthread_mutex_unlock (&unit_lock);
840 while (newunit_tos != 0)
841 if (newunit_stack[newunit_tos].unit)
843 fbuf_destroy (newunit_stack[newunit_tos].unit);
844 free (newunit_stack[newunit_tos].unit->s);
845 free (newunit_stack[newunit_tos--].unit);
848 free (newunits);
850 #ifdef HAVE_FREELOCALE
851 freelocale (c_locale);
852 #endif
856 /* High level interface to truncate a file, i.e. flush format buffers,
857 and generate an error or set some flags. Just like POSIX
858 ftruncate, returns 0 on success, -1 on failure. */
861 unit_truncate (gfc_unit *u, gfc_offset pos, st_parameter_common *common)
863 int ret;
865 /* Make sure format buffer is flushed. */
866 if (u->flags.form == FORM_FORMATTED)
868 if (u->mode == READING)
869 pos += fbuf_reset (u);
870 else
871 fbuf_flush (u, u->mode);
874 /* struncate() should flush the stream buffer if necessary, so don't
875 bother calling sflush() here. */
876 ret = struncate (u->s, pos);
878 if (ret != 0)
879 generate_error (common, LIBERROR_OS, NULL);
880 else
882 u->endfile = AT_ENDFILE;
883 u->flags.position = POSITION_APPEND;
886 return ret;
890 /* filename_from_unit()-- If the unit_number exists, return a pointer to the
891 name of the associated file, otherwise return the empty string. The caller
892 must free memory allocated for the filename string. */
894 char *
895 filename_from_unit (int n)
897 gfc_unit *u;
898 int c;
900 /* Find the unit. */
901 u = unit_root;
902 while (u != NULL)
904 c = compare (n, u->unit_number);
905 if (c < 0)
906 u = u->left;
907 if (c > 0)
908 u = u->right;
909 if (c == 0)
910 break;
913 /* Get the filename. */
914 if (u != NULL && u->filename != NULL)
915 return strdup (u->filename);
916 else
917 return (char *) NULL;
920 void
921 finish_last_advance_record (gfc_unit *u)
924 if (u->saved_pos > 0)
925 fbuf_seek (u, u->saved_pos, SEEK_CUR);
927 if (!(u->unit_number == options.stdout_unit
928 || u->unit_number == options.stderr_unit))
930 #ifdef HAVE_CRLF
931 const int len = 2;
932 #else
933 const int len = 1;
934 #endif
935 char *p = fbuf_alloc (u, len);
936 if (!p)
937 os_error ("Completing record after ADVANCE_NO failed");
938 #ifdef HAVE_CRLF
939 *(p++) = '\r';
940 #endif
941 *p = '\n';
944 fbuf_flush (u, u->mode);
948 /* Assign a negative number for NEWUNIT in OPEN statements or for
949 internal units. */
951 newunit_alloc (void)
953 __gthread_mutex_lock (&unit_lock);
954 if (!newunits)
956 newunits = xcalloc (16, 1);
957 newunit_size = 16;
960 /* Search for the next available newunit. */
961 for (int ii = newunit_lwi; ii < newunit_size; ii++)
963 if (!newunits[ii])
965 newunits[ii] = true;
966 newunit_lwi = ii + 1;
967 __gthread_mutex_unlock (&unit_lock);
968 return -ii + NEWUNIT_START;
972 /* Search failed, bump size of array and allocate the first
973 available unit. */
974 int old_size = newunit_size;
975 newunit_size *= 2;
976 newunits = xrealloc (newunits, newunit_size);
977 memset (newunits + old_size, 0, old_size);
978 newunits[old_size] = true;
979 newunit_lwi = old_size + 1;
980 __gthread_mutex_unlock (&unit_lock);
981 return -old_size + NEWUNIT_START;
985 /* Free a previously allocated newunit= unit number. unit_lock must
986 be held when calling. */
988 static void
989 newunit_free (int unit)
991 int ind = -unit + NEWUNIT_START;
992 assert(ind >= 0 && ind < newunit_size);
993 newunits[ind] = false;
994 if (ind < newunit_lwi)
995 newunit_lwi = ind;