xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/io/async.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1*4c3eb207Smrg /* Copyright (C) 2018-2020 Free Software Foundation, Inc.
2627f7eb2Smrg    Contributed by Nicolas Koenig
3627f7eb2Smrg 
4627f7eb2Smrg    This file is part of the GNU Fortran runtime library (libgfortran).
5627f7eb2Smrg 
6627f7eb2Smrg    Libgfortran is free software; you can redistribute it and/or modify
7627f7eb2Smrg    it under the terms of the GNU General Public License as published by
8627f7eb2Smrg    the Free Software Foundation; either version 3, or (at your option)
9627f7eb2Smrg    any later version.
10627f7eb2Smrg 
11627f7eb2Smrg    Libgfortran is distributed in the hope that it will be useful,
12627f7eb2Smrg    but WITHOUT ANY WARRANTY; without even the implied warranty of
13627f7eb2Smrg    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14627f7eb2Smrg    GNU General Public License for more details.
15627f7eb2Smrg 
16627f7eb2Smrg    Under Section 7 of GPL version 3, you are granted additional
17627f7eb2Smrg    permissions described in the GCC Runtime Library Exception, version
18627f7eb2Smrg    3.1, as published by the Free Software Foundation.
19627f7eb2Smrg 
20627f7eb2Smrg    You should have received a copy of the GNU General Public License and
21627f7eb2Smrg    a copy of the GCC Runtime Library Exception along with this program;
22627f7eb2Smrg    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23627f7eb2Smrg    <http://www.gnu.org/licenses/>.  */
24627f7eb2Smrg 
25627f7eb2Smrg #include "libgfortran.h"
26627f7eb2Smrg 
27627f7eb2Smrg #define _GTHREAD_USE_COND_INIT_FUNC
28627f7eb2Smrg #include "../../libgcc/gthr.h"
29627f7eb2Smrg #include "io.h"
30627f7eb2Smrg #include "fbuf.h"
31627f7eb2Smrg #include "format.h"
32627f7eb2Smrg #include "unix.h"
33627f7eb2Smrg #include <string.h>
34627f7eb2Smrg #include <assert.h>
35627f7eb2Smrg 
36627f7eb2Smrg #include <sys/types.h>
37627f7eb2Smrg 
38627f7eb2Smrg #include "async.h"
39627f7eb2Smrg #if ASYNC_IO
40627f7eb2Smrg 
41627f7eb2Smrg DEBUG_LINE (__thread const char *aio_prefix = MPREFIX);
42627f7eb2Smrg 
43627f7eb2Smrg DEBUG_LINE (__gthread_mutex_t debug_queue_lock = __GTHREAD_MUTEX_INIT;)
44627f7eb2Smrg DEBUG_LINE (aio_lock_debug *aio_debug_head = NULL;)
45627f7eb2Smrg 
46627f7eb2Smrg /* Current unit for asynchronous I/O.  Needed for error reporting.  */
47627f7eb2Smrg 
48627f7eb2Smrg __thread gfc_unit *thread_unit = NULL;
49627f7eb2Smrg 
50627f7eb2Smrg /* Queue entry for the asynchronous I/O entry.  */
51627f7eb2Smrg typedef struct transfer_queue
52627f7eb2Smrg {
53627f7eb2Smrg   enum aio_do type;
54627f7eb2Smrg   struct transfer_queue *next;
55627f7eb2Smrg   struct st_parameter_dt *new_pdt;
56627f7eb2Smrg   transfer_args arg;
57627f7eb2Smrg   _Bool has_id;
58627f7eb2Smrg   int read_flag;
59627f7eb2Smrg } transfer_queue;
60627f7eb2Smrg 
61627f7eb2Smrg struct error {
62627f7eb2Smrg   st_parameter_dt *dtp;
63627f7eb2Smrg   int id;
64627f7eb2Smrg };
65627f7eb2Smrg 
66627f7eb2Smrg /* Helper function to exchange the old vs. a new PDT.  */
67627f7eb2Smrg 
68627f7eb2Smrg static void
update_pdt(st_parameter_dt ** old,st_parameter_dt * new)69627f7eb2Smrg update_pdt (st_parameter_dt **old, st_parameter_dt *new) {
70627f7eb2Smrg   st_parameter_dt *temp;
71627f7eb2Smrg   NOTE ("Changing pdts, current_unit = %p", (void *) (new->u.p.current_unit));
72627f7eb2Smrg   temp = *old;
73627f7eb2Smrg   *old = new;
74627f7eb2Smrg   if (temp)
75627f7eb2Smrg     free (temp);
76627f7eb2Smrg }
77627f7eb2Smrg 
78627f7eb2Smrg /* Destroy an adv_cond structure.  */
79627f7eb2Smrg 
80627f7eb2Smrg static void
destroy_adv_cond(struct adv_cond * ac)81627f7eb2Smrg destroy_adv_cond (struct adv_cond *ac)
82627f7eb2Smrg {
83627f7eb2Smrg   T_ERROR (__gthread_cond_destroy, &ac->signal);
84627f7eb2Smrg }
85627f7eb2Smrg 
86627f7eb2Smrg /* Function invoked as start routine for a new asynchronous I/O unit.
87627f7eb2Smrg    Contains the main loop for accepting requests and handling them.  */
88627f7eb2Smrg 
89627f7eb2Smrg static void *
async_io(void * arg)90627f7eb2Smrg async_io (void *arg)
91627f7eb2Smrg {
92627f7eb2Smrg   DEBUG_LINE (aio_prefix = TPREFIX);
93627f7eb2Smrg   transfer_queue *ctq = NULL, *prev = NULL;
94627f7eb2Smrg   gfc_unit *u = (gfc_unit *) arg;
95627f7eb2Smrg   async_unit *au = u->au;
96627f7eb2Smrg   LOCK (&au->lock);
97627f7eb2Smrg   thread_unit = u;
98627f7eb2Smrg   au->thread = __gthread_self ();
99627f7eb2Smrg   while (true)
100627f7eb2Smrg     {
101627f7eb2Smrg       /* Main loop.  At this point, au->lock is always held. */
102627f7eb2Smrg       WAIT_SIGNAL_MUTEX (&au->work, au->tail != NULL, &au->lock);
103627f7eb2Smrg       LOCK (&au->lock);
104627f7eb2Smrg       ctq = au->head;
105627f7eb2Smrg       prev = NULL;
106627f7eb2Smrg       /* Loop over the queue entries until they are finished.  */
107627f7eb2Smrg       while (ctq)
108627f7eb2Smrg 	{
109627f7eb2Smrg 	  if (prev)
110627f7eb2Smrg 	    free (prev);
111627f7eb2Smrg 	  prev = ctq;
112627f7eb2Smrg 	  if (!au->error.has_error)
113627f7eb2Smrg 	    {
114627f7eb2Smrg 	      UNLOCK (&au->lock);
115627f7eb2Smrg 
116627f7eb2Smrg 	      switch (ctq->type)
117627f7eb2Smrg 		{
118627f7eb2Smrg 		case AIO_WRITE_DONE:
119627f7eb2Smrg 		  NOTE ("Finalizing write");
120627f7eb2Smrg 		  st_write_done_worker (au->pdt);
121627f7eb2Smrg 		  UNLOCK (&au->io_lock);
122627f7eb2Smrg 		  break;
123627f7eb2Smrg 
124627f7eb2Smrg 		case AIO_READ_DONE:
125627f7eb2Smrg 		  NOTE ("Finalizing read");
126627f7eb2Smrg 		  st_read_done_worker (au->pdt);
127627f7eb2Smrg 		  UNLOCK (&au->io_lock);
128627f7eb2Smrg 		  break;
129627f7eb2Smrg 
130627f7eb2Smrg 		case AIO_DATA_TRANSFER_INIT:
131627f7eb2Smrg 		  NOTE ("Data transfer init");
132627f7eb2Smrg 		  LOCK (&au->io_lock);
133627f7eb2Smrg 		  update_pdt (&au->pdt, ctq->new_pdt);
134627f7eb2Smrg 		  data_transfer_init_worker (au->pdt, ctq->read_flag);
135627f7eb2Smrg 		  break;
136627f7eb2Smrg 
137627f7eb2Smrg 		case AIO_TRANSFER_SCALAR:
138627f7eb2Smrg 		  NOTE ("Starting scalar transfer");
139627f7eb2Smrg 		  ctq->arg.scalar.transfer (au->pdt, ctq->arg.scalar.arg_bt,
140627f7eb2Smrg 					    ctq->arg.scalar.data,
141627f7eb2Smrg 					    ctq->arg.scalar.i,
142627f7eb2Smrg 					    ctq->arg.scalar.s1,
143627f7eb2Smrg 					    ctq->arg.scalar.s2);
144627f7eb2Smrg 		  break;
145627f7eb2Smrg 
146627f7eb2Smrg 		case AIO_TRANSFER_ARRAY:
147627f7eb2Smrg 		  NOTE ("Starting array transfer");
148627f7eb2Smrg 		  NOTE ("ctq->arg.array.desc = %p",
149627f7eb2Smrg 			(void *) (ctq->arg.array.desc));
150627f7eb2Smrg 		  transfer_array_inner (au->pdt, ctq->arg.array.desc,
151627f7eb2Smrg 					ctq->arg.array.kind,
152627f7eb2Smrg 					ctq->arg.array.charlen);
153627f7eb2Smrg 		  free (ctq->arg.array.desc);
154627f7eb2Smrg 		  break;
155627f7eb2Smrg 
156627f7eb2Smrg 		case AIO_CLOSE:
157627f7eb2Smrg 		  NOTE ("Received AIO_CLOSE");
158627f7eb2Smrg 		  LOCK (&au->lock);
159627f7eb2Smrg 		  goto finish_thread;
160627f7eb2Smrg 
161627f7eb2Smrg 		default:
162627f7eb2Smrg 		  internal_error (NULL, "Invalid queue type");
163627f7eb2Smrg 		  break;
164627f7eb2Smrg 		}
165627f7eb2Smrg 	      LOCK (&au->lock);
166627f7eb2Smrg 	      if (unlikely (au->error.has_error))
167627f7eb2Smrg 		au->error.last_good_id = au->id.low - 1;
168627f7eb2Smrg 	    }
169627f7eb2Smrg 	  else
170627f7eb2Smrg 	    {
171627f7eb2Smrg 	      if (ctq->type == AIO_WRITE_DONE || ctq->type == AIO_READ_DONE)
172627f7eb2Smrg 		{
173627f7eb2Smrg 		  UNLOCK (&au->io_lock);
174627f7eb2Smrg 		}
175627f7eb2Smrg 	      else if (ctq->type == AIO_CLOSE)
176627f7eb2Smrg 		{
177627f7eb2Smrg 		  NOTE ("Received AIO_CLOSE during error condition");
178627f7eb2Smrg 		  goto finish_thread;
179627f7eb2Smrg 		}
180627f7eb2Smrg 	    }
181627f7eb2Smrg 
182627f7eb2Smrg   	  NOTE ("Next ctq, current id: %d", au->id.low);
183627f7eb2Smrg   	  if (ctq->has_id && au->id.waiting == au->id.low++)
184627f7eb2Smrg 	    SIGNAL (&au->id.done);
185627f7eb2Smrg 
186627f7eb2Smrg 	  ctq = ctq->next;
187627f7eb2Smrg 	}
188627f7eb2Smrg       au->tail = NULL;
189627f7eb2Smrg       au->head = NULL;
190627f7eb2Smrg       au->empty = 1;
191627f7eb2Smrg       SIGNAL (&au->emptysignal);
192627f7eb2Smrg     }
193627f7eb2Smrg  finish_thread:
194627f7eb2Smrg   au->tail = NULL;
195627f7eb2Smrg   au->head = NULL;
196627f7eb2Smrg   au->empty = 1;
197627f7eb2Smrg   SIGNAL (&au->emptysignal);
198627f7eb2Smrg   free (ctq);
199627f7eb2Smrg   UNLOCK (&au->lock);
200627f7eb2Smrg   return NULL;
201627f7eb2Smrg }
202627f7eb2Smrg 
203627f7eb2Smrg /* Free an asynchronous unit.  */
204627f7eb2Smrg 
205627f7eb2Smrg static void
free_async_unit(async_unit * au)206627f7eb2Smrg free_async_unit (async_unit *au)
207627f7eb2Smrg {
208627f7eb2Smrg   if (au->tail)
209627f7eb2Smrg     internal_error (NULL, "Trying to free nonempty asynchronous unit");
210627f7eb2Smrg 
211627f7eb2Smrg   destroy_adv_cond (&au->work);
212627f7eb2Smrg   destroy_adv_cond (&au->emptysignal);
213627f7eb2Smrg   destroy_adv_cond (&au->id.done);
214627f7eb2Smrg   T_ERROR (__gthread_mutex_destroy, &au->lock);
215627f7eb2Smrg   free (au);
216627f7eb2Smrg }
217627f7eb2Smrg 
218627f7eb2Smrg /* Initialize an adv_cond structure.  */
219627f7eb2Smrg 
220627f7eb2Smrg static void
init_adv_cond(struct adv_cond * ac)221627f7eb2Smrg init_adv_cond (struct adv_cond *ac)
222627f7eb2Smrg {
223627f7eb2Smrg   ac->pending = 0;
224627f7eb2Smrg   __GTHREAD_COND_INIT_FUNCTION (&ac->signal);
225627f7eb2Smrg }
226627f7eb2Smrg 
227627f7eb2Smrg /* Initialize an asyncronous unit, returning zero on success,
228627f7eb2Smrg  nonzero on failure.  It also sets u->au.  */
229627f7eb2Smrg 
230627f7eb2Smrg void
init_async_unit(gfc_unit * u)231627f7eb2Smrg init_async_unit (gfc_unit *u)
232627f7eb2Smrg {
233627f7eb2Smrg   async_unit *au;
234627f7eb2Smrg   if (!__gthread_active_p ())
235627f7eb2Smrg     {
236627f7eb2Smrg       u->au = NULL;
237627f7eb2Smrg       return;
238627f7eb2Smrg     }
239627f7eb2Smrg 
240627f7eb2Smrg   au = (async_unit *) xmalloc (sizeof (async_unit));
241627f7eb2Smrg   u->au = au;
242627f7eb2Smrg   init_adv_cond (&au->work);
243627f7eb2Smrg   init_adv_cond (&au->emptysignal);
244627f7eb2Smrg   __GTHREAD_MUTEX_INIT_FUNCTION (&au->lock);
245627f7eb2Smrg   __GTHREAD_MUTEX_INIT_FUNCTION (&au->io_lock);
246627f7eb2Smrg   LOCK (&au->lock);
247627f7eb2Smrg   T_ERROR (__gthread_create, &au->thread, &async_io, (void *) u);
248627f7eb2Smrg   au->pdt = NULL;
249627f7eb2Smrg   au->head = NULL;
250627f7eb2Smrg   au->tail = NULL;
251627f7eb2Smrg   au->empty = true;
252627f7eb2Smrg   au->id.waiting = -1;
253627f7eb2Smrg   au->id.low = 0;
254627f7eb2Smrg   au->id.high = 0;
255627f7eb2Smrg   au->error.fatal_error = 0;
256627f7eb2Smrg   au->error.has_error = 0;
257627f7eb2Smrg   au->error.last_good_id = 0;
258627f7eb2Smrg   init_adv_cond (&au->id.done);
259627f7eb2Smrg   UNLOCK (&au->lock);
260627f7eb2Smrg }
261627f7eb2Smrg 
262627f7eb2Smrg /* Enqueue a transfer statement.  */
263627f7eb2Smrg 
264627f7eb2Smrg void
enqueue_transfer(async_unit * au,transfer_args * arg,enum aio_do type)265627f7eb2Smrg enqueue_transfer (async_unit *au, transfer_args *arg, enum aio_do type)
266627f7eb2Smrg {
267627f7eb2Smrg   transfer_queue *tq = calloc (sizeof (transfer_queue), 1);
268627f7eb2Smrg   tq->arg = *arg;
269627f7eb2Smrg   tq->type = type;
270627f7eb2Smrg   tq->has_id = 0;
271627f7eb2Smrg   LOCK (&au->lock);
272627f7eb2Smrg   if (!au->tail)
273627f7eb2Smrg     au->head = tq;
274627f7eb2Smrg   else
275627f7eb2Smrg     au->tail->next = tq;
276627f7eb2Smrg   au->tail = tq;
277627f7eb2Smrg   REVOKE_SIGNAL (&(au->emptysignal));
278627f7eb2Smrg   au->empty = false;
279627f7eb2Smrg   SIGNAL (&au->work);
280627f7eb2Smrg   UNLOCK (&au->lock);
281627f7eb2Smrg }
282627f7eb2Smrg 
283627f7eb2Smrg /* Enqueue an st_write_done or st_read_done which contains an ID.  */
284627f7eb2Smrg 
285627f7eb2Smrg int
enqueue_done_id(async_unit * au,enum aio_do type)286627f7eb2Smrg enqueue_done_id (async_unit *au, enum aio_do type)
287627f7eb2Smrg {
288627f7eb2Smrg   int ret;
289627f7eb2Smrg   transfer_queue *tq = calloc (sizeof (transfer_queue), 1);
290627f7eb2Smrg 
291627f7eb2Smrg   tq->type = type;
292627f7eb2Smrg   tq->has_id = 1;
293627f7eb2Smrg   LOCK (&au->lock);
294627f7eb2Smrg   if (!au->tail)
295627f7eb2Smrg     au->head = tq;
296627f7eb2Smrg   else
297627f7eb2Smrg     au->tail->next = tq;
298627f7eb2Smrg   au->tail = tq;
299627f7eb2Smrg   REVOKE_SIGNAL (&(au->emptysignal));
300627f7eb2Smrg   au->empty = false;
301627f7eb2Smrg   ret = au->id.high++;
302627f7eb2Smrg   NOTE ("Enqueue id: %d", ret);
303627f7eb2Smrg   SIGNAL (&au->work);
304627f7eb2Smrg   UNLOCK (&au->lock);
305627f7eb2Smrg   return ret;
306627f7eb2Smrg }
307627f7eb2Smrg 
308627f7eb2Smrg /* Enqueue an st_write_done or st_read_done without an ID.  */
309627f7eb2Smrg 
310627f7eb2Smrg void
enqueue_done(async_unit * au,enum aio_do type)311627f7eb2Smrg enqueue_done (async_unit *au, enum aio_do type)
312627f7eb2Smrg {
313627f7eb2Smrg   transfer_queue *tq = calloc (sizeof (transfer_queue), 1);
314627f7eb2Smrg   tq->type = type;
315627f7eb2Smrg   tq->has_id = 0;
316627f7eb2Smrg   LOCK (&au->lock);
317627f7eb2Smrg   if (!au->tail)
318627f7eb2Smrg     au->head = tq;
319627f7eb2Smrg   else
320627f7eb2Smrg     au->tail->next = tq;
321627f7eb2Smrg   au->tail = tq;
322627f7eb2Smrg   REVOKE_SIGNAL (&(au->emptysignal));
323627f7eb2Smrg   au->empty = false;
324627f7eb2Smrg   SIGNAL (&au->work);
325627f7eb2Smrg   UNLOCK (&au->lock);
326627f7eb2Smrg }
327627f7eb2Smrg 
328627f7eb2Smrg /* Enqueue a CLOSE statement.  */
329627f7eb2Smrg 
330627f7eb2Smrg void
enqueue_close(async_unit * au)331627f7eb2Smrg enqueue_close (async_unit *au)
332627f7eb2Smrg {
333627f7eb2Smrg   transfer_queue *tq = calloc (sizeof (transfer_queue), 1);
334627f7eb2Smrg 
335627f7eb2Smrg   tq->type = AIO_CLOSE;
336627f7eb2Smrg   LOCK (&au->lock);
337627f7eb2Smrg   if (!au->tail)
338627f7eb2Smrg     au->head = tq;
339627f7eb2Smrg   else
340627f7eb2Smrg     au->tail->next = tq;
341627f7eb2Smrg   au->tail = tq;
342627f7eb2Smrg   REVOKE_SIGNAL (&(au->emptysignal));
343627f7eb2Smrg   au->empty = false;
344627f7eb2Smrg   SIGNAL (&au->work);
345627f7eb2Smrg   UNLOCK (&au->lock);
346627f7eb2Smrg }
347627f7eb2Smrg 
348627f7eb2Smrg /* The asynchronous unit keeps the currently active PDT around.
349627f7eb2Smrg    This function changes that to the current one.  */
350627f7eb2Smrg 
351627f7eb2Smrg void
enqueue_data_transfer_init(async_unit * au,st_parameter_dt * dt,int read_flag)352627f7eb2Smrg enqueue_data_transfer_init (async_unit *au, st_parameter_dt *dt, int read_flag)
353627f7eb2Smrg {
354627f7eb2Smrg   st_parameter_dt *new = xmalloc (sizeof (st_parameter_dt));
355627f7eb2Smrg   transfer_queue *tq = xmalloc (sizeof (transfer_queue));
356627f7eb2Smrg 
357627f7eb2Smrg   memcpy ((void *) new, (void *) dt, sizeof (st_parameter_dt));
358627f7eb2Smrg 
359627f7eb2Smrg   NOTE ("dt->internal_unit_desc = %p", dt->internal_unit_desc);
360627f7eb2Smrg   NOTE ("common.flags & mask = %d", dt->common.flags & IOPARM_LIBRETURN_MASK);
361627f7eb2Smrg   tq->next = NULL;
362627f7eb2Smrg   tq->type = AIO_DATA_TRANSFER_INIT;
363627f7eb2Smrg   tq->read_flag = read_flag;
364627f7eb2Smrg   tq->has_id = 0;
365627f7eb2Smrg   tq->new_pdt = new;
366627f7eb2Smrg   LOCK (&au->lock);
367627f7eb2Smrg 
368627f7eb2Smrg   if (!au->tail)
369627f7eb2Smrg     au->head = tq;
370627f7eb2Smrg   else
371627f7eb2Smrg     au->tail->next = tq;
372627f7eb2Smrg   au->tail = tq;
373627f7eb2Smrg   REVOKE_SIGNAL (&(au->emptysignal));
374627f7eb2Smrg   au->empty = false;
375627f7eb2Smrg   SIGNAL (&au->work);
376627f7eb2Smrg   UNLOCK (&au->lock);
377627f7eb2Smrg }
378627f7eb2Smrg 
379627f7eb2Smrg /* Collect the errors that may have happened asynchronously.  Return true if
380627f7eb2Smrg    an error has been encountered.  */
381627f7eb2Smrg 
382627f7eb2Smrg bool
collect_async_errors(st_parameter_common * cmp,async_unit * au)383627f7eb2Smrg collect_async_errors (st_parameter_common *cmp, async_unit *au)
384627f7eb2Smrg {
385627f7eb2Smrg   bool has_error = au->error.has_error;
386627f7eb2Smrg 
387627f7eb2Smrg   if (has_error)
388627f7eb2Smrg     {
389627f7eb2Smrg       if (generate_error_common (cmp, au->error.family, au->error.message))
390627f7eb2Smrg 	{
391627f7eb2Smrg 	  au->error.has_error = 0;
392627f7eb2Smrg 	  au->error.cmp = NULL;
393627f7eb2Smrg 	}
394627f7eb2Smrg       else
395627f7eb2Smrg 	{
396627f7eb2Smrg 	  /* The program will exit later.  */
397627f7eb2Smrg 	  au->error.fatal_error = true;
398627f7eb2Smrg 	}
399627f7eb2Smrg     }
400627f7eb2Smrg   return has_error;
401627f7eb2Smrg }
402627f7eb2Smrg 
403627f7eb2Smrg /* Perform a wait operation on an asynchronous unit with an ID specified,
404627f7eb2Smrg    which means collecting the errors that may have happened asynchronously.
405627f7eb2Smrg    Return true if an error has been encountered.  */
406627f7eb2Smrg 
407627f7eb2Smrg bool
async_wait_id(st_parameter_common * cmp,async_unit * au,int i)408627f7eb2Smrg async_wait_id (st_parameter_common *cmp, async_unit *au, int i)
409627f7eb2Smrg {
410627f7eb2Smrg   bool ret;
411627f7eb2Smrg 
412627f7eb2Smrg   if (au == NULL)
413627f7eb2Smrg     return false;
414627f7eb2Smrg 
415627f7eb2Smrg   if (cmp == NULL)
416627f7eb2Smrg     cmp = au->error.cmp;
417627f7eb2Smrg 
418627f7eb2Smrg   if (au->error.has_error)
419627f7eb2Smrg     {
420627f7eb2Smrg       if (i <= au->error.last_good_id)
421627f7eb2Smrg 	return false;
422627f7eb2Smrg 
423627f7eb2Smrg       return collect_async_errors (cmp, au);
424627f7eb2Smrg     }
425627f7eb2Smrg 
426627f7eb2Smrg   LOCK (&au->lock);
427*4c3eb207Smrg   if (i > au->id.high)
428*4c3eb207Smrg     {
429*4c3eb207Smrg       generate_error_common (cmp, LIBERROR_BAD_WAIT_ID, NULL);
430*4c3eb207Smrg       UNLOCK (&au->lock);
431*4c3eb207Smrg       return true;
432*4c3eb207Smrg     }
433*4c3eb207Smrg 
434627f7eb2Smrg   NOTE ("Waiting for id %d", i);
435627f7eb2Smrg   if (au->id.waiting < i)
436627f7eb2Smrg     au->id.waiting = i;
437627f7eb2Smrg   SIGNAL (&(au->work));
438627f7eb2Smrg   WAIT_SIGNAL_MUTEX (&(au->id.done),
439627f7eb2Smrg 		     (au->id.low >= au->id.waiting || au->empty), &au->lock);
440627f7eb2Smrg   LOCK (&au->lock);
441627f7eb2Smrg   ret = collect_async_errors (cmp, au);
442627f7eb2Smrg   UNLOCK (&au->lock);
443627f7eb2Smrg   return ret;
444627f7eb2Smrg }
445627f7eb2Smrg 
446627f7eb2Smrg /* Perform a wait operation an an asynchronous unit without an ID.  */
447627f7eb2Smrg 
448627f7eb2Smrg bool
async_wait(st_parameter_common * cmp,async_unit * au)449627f7eb2Smrg async_wait (st_parameter_common *cmp, async_unit *au)
450627f7eb2Smrg {
451627f7eb2Smrg   bool ret;
452627f7eb2Smrg 
453627f7eb2Smrg   if (au == NULL)
454627f7eb2Smrg     return false;
455627f7eb2Smrg 
456627f7eb2Smrg   if (cmp == NULL)
457627f7eb2Smrg     cmp = au->error.cmp;
458627f7eb2Smrg 
459627f7eb2Smrg   LOCK (&(au->lock));
460627f7eb2Smrg   SIGNAL (&(au->work));
461627f7eb2Smrg 
462627f7eb2Smrg   if (au->empty)
463627f7eb2Smrg     {
464627f7eb2Smrg       ret = collect_async_errors (cmp, au);
465627f7eb2Smrg       UNLOCK (&au->lock);
466627f7eb2Smrg       return ret;
467627f7eb2Smrg     }
468627f7eb2Smrg 
469627f7eb2Smrg   WAIT_SIGNAL_MUTEX (&(au->emptysignal), (au->empty), &au->lock);
470627f7eb2Smrg   ret = collect_async_errors (cmp, au);
471627f7eb2Smrg   return ret;
472627f7eb2Smrg }
473627f7eb2Smrg 
474627f7eb2Smrg /* Close an asynchronous unit.  */
475627f7eb2Smrg 
476627f7eb2Smrg void
async_close(async_unit * au)477627f7eb2Smrg async_close (async_unit *au)
478627f7eb2Smrg {
479627f7eb2Smrg   if (au == NULL)
480627f7eb2Smrg     return;
481627f7eb2Smrg 
482627f7eb2Smrg   NOTE ("Closing async unit");
483627f7eb2Smrg   enqueue_close (au);
484627f7eb2Smrg   T_ERROR (__gthread_join, au->thread, NULL);
485627f7eb2Smrg   free_async_unit (au);
486627f7eb2Smrg }
487627f7eb2Smrg 
488627f7eb2Smrg #else
489627f7eb2Smrg 
490627f7eb2Smrg /* Only set u->au to NULL so no async I/O will happen.  */
491627f7eb2Smrg 
492627f7eb2Smrg void
init_async_unit(gfc_unit * u)493627f7eb2Smrg init_async_unit (gfc_unit *u)
494627f7eb2Smrg {
495627f7eb2Smrg   u->au = NULL;
496627f7eb2Smrg   return;
497627f7eb2Smrg }
498627f7eb2Smrg 
499627f7eb2Smrg /* Do-nothing function, which will not be called.  */
500627f7eb2Smrg 
501627f7eb2Smrg void
enqueue_transfer(async_unit * au,transfer_args * arg,enum aio_do type)502627f7eb2Smrg enqueue_transfer (async_unit *au, transfer_args *arg, enum aio_do type)
503627f7eb2Smrg {
504627f7eb2Smrg   return;
505627f7eb2Smrg }
506627f7eb2Smrg 
507627f7eb2Smrg /* Do-nothing function, which will not be called.  */
508627f7eb2Smrg 
509627f7eb2Smrg int
enqueue_done_id(async_unit * au,enum aio_do type)510627f7eb2Smrg enqueue_done_id (async_unit *au, enum aio_do type)
511627f7eb2Smrg {
512627f7eb2Smrg   return 0;
513627f7eb2Smrg }
514627f7eb2Smrg 
515627f7eb2Smrg /* Do-nothing function, which will not be called.  */
516627f7eb2Smrg 
517627f7eb2Smrg void
enqueue_done(async_unit * au,enum aio_do type)518627f7eb2Smrg enqueue_done (async_unit *au, enum aio_do type)
519627f7eb2Smrg {
520627f7eb2Smrg   return;
521627f7eb2Smrg }
522627f7eb2Smrg 
523627f7eb2Smrg /* Do-nothing function, which will not be called.  */
524627f7eb2Smrg 
525627f7eb2Smrg void
enqueue_close(async_unit * au)526627f7eb2Smrg enqueue_close (async_unit *au)
527627f7eb2Smrg {
528627f7eb2Smrg   return;
529627f7eb2Smrg }
530627f7eb2Smrg 
531627f7eb2Smrg /* Do-nothing function, which will not be called.  */
532627f7eb2Smrg 
533627f7eb2Smrg void
enqueue_data_transfer_init(async_unit * au,st_parameter_dt * dt,int read_flag)534627f7eb2Smrg enqueue_data_transfer_init (async_unit *au, st_parameter_dt *dt, int read_flag)
535627f7eb2Smrg {
536627f7eb2Smrg   return;
537627f7eb2Smrg }
538627f7eb2Smrg 
539627f7eb2Smrg /* Do-nothing function, which will not be called.  */
540627f7eb2Smrg 
541627f7eb2Smrg bool
collect_async_errors(st_parameter_common * cmp,async_unit * au)542627f7eb2Smrg collect_async_errors (st_parameter_common *cmp, async_unit *au)
543627f7eb2Smrg {
544627f7eb2Smrg   return false;
545627f7eb2Smrg }
546627f7eb2Smrg 
547627f7eb2Smrg /* Do-nothing function, which will not be called.  */
548627f7eb2Smrg 
549627f7eb2Smrg bool
async_wait_id(st_parameter_common * cmp,async_unit * au,int i)550627f7eb2Smrg async_wait_id (st_parameter_common *cmp, async_unit *au, int i)
551627f7eb2Smrg {
552627f7eb2Smrg   return false;
553627f7eb2Smrg }
554627f7eb2Smrg 
555627f7eb2Smrg /* Do-nothing function, which will not be called.  */
556627f7eb2Smrg 
557627f7eb2Smrg bool
async_wait(st_parameter_common * cmp,async_unit * au)558627f7eb2Smrg async_wait (st_parameter_common *cmp, async_unit *au)
559627f7eb2Smrg {
560627f7eb2Smrg   return false;
561627f7eb2Smrg }
562627f7eb2Smrg 
563627f7eb2Smrg /* Do-nothing function, which will not be called.  */
564627f7eb2Smrg 
565627f7eb2Smrg void
async_close(async_unit * au)566627f7eb2Smrg async_close (async_unit *au)
567627f7eb2Smrg {
568627f7eb2Smrg   return;
569627f7eb2Smrg }
570627f7eb2Smrg 
571627f7eb2Smrg #endif
572