xref: /netbsd-src/external/gpl3/gcc/dist/libgfortran/io/async.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1*b1e83836Smrg /* Copyright (C) 2018-2022 Free Software Foundation, Inc.
2181254a7Smrg    Contributed by Nicolas Koenig
3181254a7Smrg 
4181254a7Smrg    This file is part of the GNU Fortran runtime library (libgfortran).
5181254a7Smrg 
6181254a7Smrg    Libgfortran is free software; you can redistribute it and/or modify
7181254a7Smrg    it under the terms of the GNU General Public License as published by
8181254a7Smrg    the Free Software Foundation; either version 3, or (at your option)
9181254a7Smrg    any later version.
10181254a7Smrg 
11181254a7Smrg    Libgfortran is distributed in the hope that it will be useful,
12181254a7Smrg    but WITHOUT ANY WARRANTY; without even the implied warranty of
13181254a7Smrg    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14181254a7Smrg    GNU General Public License for more details.
15181254a7Smrg 
16181254a7Smrg    Under Section 7 of GPL version 3, you are granted additional
17181254a7Smrg    permissions described in the GCC Runtime Library Exception, version
18181254a7Smrg    3.1, as published by the Free Software Foundation.
19181254a7Smrg 
20181254a7Smrg    You should have received a copy of the GNU General Public License and
21181254a7Smrg    a copy of the GCC Runtime Library Exception along with this program;
22181254a7Smrg    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23181254a7Smrg    <http://www.gnu.org/licenses/>.  */
24181254a7Smrg 
25181254a7Smrg #include "libgfortran.h"
26181254a7Smrg 
27181254a7Smrg #define _GTHREAD_USE_COND_INIT_FUNC
28181254a7Smrg #include "../../libgcc/gthr.h"
29181254a7Smrg #include "io.h"
30181254a7Smrg #include "fbuf.h"
31181254a7Smrg #include "format.h"
32181254a7Smrg #include "unix.h"
33181254a7Smrg #include <string.h>
34181254a7Smrg #include <assert.h>
35181254a7Smrg 
36181254a7Smrg #include <sys/types.h>
37181254a7Smrg 
38181254a7Smrg #include "async.h"
39181254a7Smrg #if ASYNC_IO
40181254a7Smrg 
41181254a7Smrg DEBUG_LINE (__thread const char *aio_prefix = MPREFIX);
42181254a7Smrg 
43181254a7Smrg DEBUG_LINE (__gthread_mutex_t debug_queue_lock = __GTHREAD_MUTEX_INIT;)
44181254a7Smrg DEBUG_LINE (aio_lock_debug *aio_debug_head = NULL;)
45181254a7Smrg 
46181254a7Smrg /* Current unit for asynchronous I/O.  Needed for error reporting.  */
47181254a7Smrg 
48181254a7Smrg __thread gfc_unit *thread_unit = NULL;
49181254a7Smrg 
50181254a7Smrg /* Queue entry for the asynchronous I/O entry.  */
51181254a7Smrg typedef struct transfer_queue
52181254a7Smrg {
53181254a7Smrg   enum aio_do type;
54181254a7Smrg   struct transfer_queue *next;
55181254a7Smrg   struct st_parameter_dt *new_pdt;
56181254a7Smrg   transfer_args arg;
57181254a7Smrg   _Bool has_id;
58181254a7Smrg   int read_flag;
59181254a7Smrg } transfer_queue;
60181254a7Smrg 
61181254a7Smrg struct error {
62181254a7Smrg   st_parameter_dt *dtp;
63181254a7Smrg   int id;
64181254a7Smrg };
65181254a7Smrg 
66181254a7Smrg /* Helper function to exchange the old vs. a new PDT.  */
67181254a7Smrg 
68181254a7Smrg static void
update_pdt(st_parameter_dt ** old,st_parameter_dt * new)69181254a7Smrg update_pdt (st_parameter_dt **old, st_parameter_dt *new) {
70181254a7Smrg   st_parameter_dt *temp;
71181254a7Smrg   NOTE ("Changing pdts, current_unit = %p", (void *) (new->u.p.current_unit));
72181254a7Smrg   temp = *old;
73181254a7Smrg   *old = new;
74181254a7Smrg   if (temp)
75181254a7Smrg     free (temp);
76181254a7Smrg }
77181254a7Smrg 
78181254a7Smrg /* Destroy an adv_cond structure.  */
79181254a7Smrg 
80181254a7Smrg static void
destroy_adv_cond(struct adv_cond * ac)81181254a7Smrg destroy_adv_cond (struct adv_cond *ac)
82181254a7Smrg {
83181254a7Smrg   T_ERROR (__gthread_cond_destroy, &ac->signal);
84181254a7Smrg }
85181254a7Smrg 
86181254a7Smrg /* Function invoked as start routine for a new asynchronous I/O unit.
87181254a7Smrg    Contains the main loop for accepting requests and handling them.  */
88181254a7Smrg 
89181254a7Smrg static void *
async_io(void * arg)90181254a7Smrg async_io (void *arg)
91181254a7Smrg {
92181254a7Smrg   DEBUG_LINE (aio_prefix = TPREFIX);
93181254a7Smrg   transfer_queue *ctq = NULL, *prev = NULL;
94181254a7Smrg   gfc_unit *u = (gfc_unit *) arg;
95181254a7Smrg   async_unit *au = u->au;
96181254a7Smrg   LOCK (&au->lock);
97181254a7Smrg   thread_unit = u;
98181254a7Smrg   au->thread = __gthread_self ();
99181254a7Smrg   while (true)
100181254a7Smrg     {
101181254a7Smrg       /* Main loop.  At this point, au->lock is always held. */
102181254a7Smrg       WAIT_SIGNAL_MUTEX (&au->work, au->tail != NULL, &au->lock);
103181254a7Smrg       LOCK (&au->lock);
104181254a7Smrg       ctq = au->head;
105181254a7Smrg       prev = NULL;
106181254a7Smrg       /* Loop over the queue entries until they are finished.  */
107181254a7Smrg       while (ctq)
108181254a7Smrg 	{
109181254a7Smrg 	  if (prev)
110181254a7Smrg 	    free (prev);
111181254a7Smrg 	  prev = ctq;
112181254a7Smrg 	  if (!au->error.has_error)
113181254a7Smrg 	    {
114181254a7Smrg 	      UNLOCK (&au->lock);
115181254a7Smrg 
116181254a7Smrg 	      switch (ctq->type)
117181254a7Smrg 		{
118181254a7Smrg 		case AIO_WRITE_DONE:
119181254a7Smrg 		  NOTE ("Finalizing write");
120*b1e83836Smrg 		  st_write_done_worker (au->pdt, false);
121181254a7Smrg 		  UNLOCK (&au->io_lock);
122181254a7Smrg 		  break;
123181254a7Smrg 
124181254a7Smrg 		case AIO_READ_DONE:
125181254a7Smrg 		  NOTE ("Finalizing read");
126*b1e83836Smrg 		  st_read_done_worker (au->pdt, false);
127181254a7Smrg 		  UNLOCK (&au->io_lock);
128181254a7Smrg 		  break;
129181254a7Smrg 
130181254a7Smrg 		case AIO_DATA_TRANSFER_INIT:
131181254a7Smrg 		  NOTE ("Data transfer init");
132181254a7Smrg 		  LOCK (&au->io_lock);
133181254a7Smrg 		  update_pdt (&au->pdt, ctq->new_pdt);
134181254a7Smrg 		  data_transfer_init_worker (au->pdt, ctq->read_flag);
135181254a7Smrg 		  break;
136181254a7Smrg 
137181254a7Smrg 		case AIO_TRANSFER_SCALAR:
138181254a7Smrg 		  NOTE ("Starting scalar transfer");
139181254a7Smrg 		  ctq->arg.scalar.transfer (au->pdt, ctq->arg.scalar.arg_bt,
140181254a7Smrg 					    ctq->arg.scalar.data,
141181254a7Smrg 					    ctq->arg.scalar.i,
142181254a7Smrg 					    ctq->arg.scalar.s1,
143181254a7Smrg 					    ctq->arg.scalar.s2);
144181254a7Smrg 		  break;
145181254a7Smrg 
146181254a7Smrg 		case AIO_TRANSFER_ARRAY:
147181254a7Smrg 		  NOTE ("Starting array transfer");
148181254a7Smrg 		  NOTE ("ctq->arg.array.desc = %p",
149181254a7Smrg 			(void *) (ctq->arg.array.desc));
150181254a7Smrg 		  transfer_array_inner (au->pdt, ctq->arg.array.desc,
151181254a7Smrg 					ctq->arg.array.kind,
152181254a7Smrg 					ctq->arg.array.charlen);
153181254a7Smrg 		  free (ctq->arg.array.desc);
154181254a7Smrg 		  break;
155181254a7Smrg 
156181254a7Smrg 		case AIO_CLOSE:
157181254a7Smrg 		  NOTE ("Received AIO_CLOSE");
158181254a7Smrg 		  LOCK (&au->lock);
159181254a7Smrg 		  goto finish_thread;
160181254a7Smrg 
161181254a7Smrg 		default:
162181254a7Smrg 		  internal_error (NULL, "Invalid queue type");
163181254a7Smrg 		  break;
164181254a7Smrg 		}
165181254a7Smrg 	      LOCK (&au->lock);
166181254a7Smrg 	      if (unlikely (au->error.has_error))
167181254a7Smrg 		au->error.last_good_id = au->id.low - 1;
168181254a7Smrg 	    }
169181254a7Smrg 	  else
170181254a7Smrg 	    {
171181254a7Smrg 	      if (ctq->type == AIO_WRITE_DONE || ctq->type == AIO_READ_DONE)
172181254a7Smrg 		{
173181254a7Smrg 		  UNLOCK (&au->io_lock);
174181254a7Smrg 		}
175181254a7Smrg 	      else if (ctq->type == AIO_CLOSE)
176181254a7Smrg 		{
177181254a7Smrg 		  NOTE ("Received AIO_CLOSE during error condition");
178181254a7Smrg 		  goto finish_thread;
179181254a7Smrg 		}
180181254a7Smrg 	    }
181181254a7Smrg 
182181254a7Smrg   	  NOTE ("Next ctq, current id: %d", au->id.low);
183181254a7Smrg   	  if (ctq->has_id && au->id.waiting == au->id.low++)
184181254a7Smrg 	    SIGNAL (&au->id.done);
185181254a7Smrg 
186181254a7Smrg 	  ctq = ctq->next;
187181254a7Smrg 	}
188181254a7Smrg       au->tail = NULL;
189181254a7Smrg       au->head = NULL;
190181254a7Smrg       au->empty = 1;
191181254a7Smrg       SIGNAL (&au->emptysignal);
192181254a7Smrg     }
193181254a7Smrg  finish_thread:
194181254a7Smrg   au->tail = NULL;
195181254a7Smrg   au->head = NULL;
196181254a7Smrg   au->empty = 1;
197181254a7Smrg   SIGNAL (&au->emptysignal);
198181254a7Smrg   free (ctq);
199181254a7Smrg   UNLOCK (&au->lock);
200181254a7Smrg   return NULL;
201181254a7Smrg }
202181254a7Smrg 
203181254a7Smrg /* Free an asynchronous unit.  */
204181254a7Smrg 
205181254a7Smrg static void
free_async_unit(async_unit * au)206181254a7Smrg free_async_unit (async_unit *au)
207181254a7Smrg {
208181254a7Smrg   if (au->tail)
209181254a7Smrg     internal_error (NULL, "Trying to free nonempty asynchronous unit");
210181254a7Smrg 
211181254a7Smrg   destroy_adv_cond (&au->work);
212181254a7Smrg   destroy_adv_cond (&au->emptysignal);
213181254a7Smrg   destroy_adv_cond (&au->id.done);
214181254a7Smrg   T_ERROR (__gthread_mutex_destroy, &au->lock);
215181254a7Smrg   free (au);
216181254a7Smrg }
217181254a7Smrg 
218181254a7Smrg /* Initialize an adv_cond structure.  */
219181254a7Smrg 
220181254a7Smrg static void
init_adv_cond(struct adv_cond * ac)221181254a7Smrg init_adv_cond (struct adv_cond *ac)
222181254a7Smrg {
223181254a7Smrg   ac->pending = 0;
224181254a7Smrg   __GTHREAD_COND_INIT_FUNCTION (&ac->signal);
225181254a7Smrg }
226181254a7Smrg 
227181254a7Smrg /* Initialize an asyncronous unit, returning zero on success,
228181254a7Smrg  nonzero on failure.  It also sets u->au.  */
229181254a7Smrg 
230181254a7Smrg void
init_async_unit(gfc_unit * u)231181254a7Smrg init_async_unit (gfc_unit *u)
232181254a7Smrg {
233181254a7Smrg   async_unit *au;
234181254a7Smrg   if (!__gthread_active_p ())
235181254a7Smrg     {
236181254a7Smrg       u->au = NULL;
237181254a7Smrg       return;
238181254a7Smrg     }
239181254a7Smrg 
240181254a7Smrg   au = (async_unit *) xmalloc (sizeof (async_unit));
241181254a7Smrg   u->au = au;
242181254a7Smrg   init_adv_cond (&au->work);
243181254a7Smrg   init_adv_cond (&au->emptysignal);
244181254a7Smrg   __GTHREAD_MUTEX_INIT_FUNCTION (&au->lock);
245181254a7Smrg   __GTHREAD_MUTEX_INIT_FUNCTION (&au->io_lock);
246181254a7Smrg   LOCK (&au->lock);
247181254a7Smrg   T_ERROR (__gthread_create, &au->thread, &async_io, (void *) u);
248181254a7Smrg   au->pdt = NULL;
249181254a7Smrg   au->head = NULL;
250181254a7Smrg   au->tail = NULL;
251181254a7Smrg   au->empty = true;
252181254a7Smrg   au->id.waiting = -1;
253181254a7Smrg   au->id.low = 0;
254181254a7Smrg   au->id.high = 0;
255181254a7Smrg   au->error.fatal_error = 0;
256181254a7Smrg   au->error.has_error = 0;
257181254a7Smrg   au->error.last_good_id = 0;
258181254a7Smrg   init_adv_cond (&au->id.done);
259181254a7Smrg   UNLOCK (&au->lock);
260181254a7Smrg }
261181254a7Smrg 
262181254a7Smrg /* Enqueue a transfer statement.  */
263181254a7Smrg 
264181254a7Smrg void
enqueue_transfer(async_unit * au,transfer_args * arg,enum aio_do type)265181254a7Smrg enqueue_transfer (async_unit *au, transfer_args *arg, enum aio_do type)
266181254a7Smrg {
267181254a7Smrg   transfer_queue *tq = calloc (sizeof (transfer_queue), 1);
268181254a7Smrg   tq->arg = *arg;
269181254a7Smrg   tq->type = type;
270181254a7Smrg   tq->has_id = 0;
271181254a7Smrg   LOCK (&au->lock);
272181254a7Smrg   if (!au->tail)
273181254a7Smrg     au->head = tq;
274181254a7Smrg   else
275181254a7Smrg     au->tail->next = tq;
276181254a7Smrg   au->tail = tq;
277181254a7Smrg   REVOKE_SIGNAL (&(au->emptysignal));
278181254a7Smrg   au->empty = false;
279181254a7Smrg   SIGNAL (&au->work);
280181254a7Smrg   UNLOCK (&au->lock);
281181254a7Smrg }
282181254a7Smrg 
283181254a7Smrg /* Enqueue an st_write_done or st_read_done which contains an ID.  */
284181254a7Smrg 
285181254a7Smrg int
enqueue_done_id(async_unit * au,enum aio_do type)286181254a7Smrg enqueue_done_id (async_unit *au, enum aio_do type)
287181254a7Smrg {
288181254a7Smrg   int ret;
289181254a7Smrg   transfer_queue *tq = calloc (sizeof (transfer_queue), 1);
290181254a7Smrg 
291181254a7Smrg   tq->type = type;
292181254a7Smrg   tq->has_id = 1;
293181254a7Smrg   LOCK (&au->lock);
294181254a7Smrg   if (!au->tail)
295181254a7Smrg     au->head = tq;
296181254a7Smrg   else
297181254a7Smrg     au->tail->next = tq;
298181254a7Smrg   au->tail = tq;
299181254a7Smrg   REVOKE_SIGNAL (&(au->emptysignal));
300181254a7Smrg   au->empty = false;
301181254a7Smrg   ret = au->id.high++;
302181254a7Smrg   NOTE ("Enqueue id: %d", ret);
303181254a7Smrg   SIGNAL (&au->work);
304181254a7Smrg   UNLOCK (&au->lock);
305181254a7Smrg   return ret;
306181254a7Smrg }
307181254a7Smrg 
308181254a7Smrg /* Enqueue an st_write_done or st_read_done without an ID.  */
309181254a7Smrg 
310181254a7Smrg void
enqueue_done(async_unit * au,enum aio_do type)311181254a7Smrg enqueue_done (async_unit *au, enum aio_do type)
312181254a7Smrg {
313181254a7Smrg   transfer_queue *tq = calloc (sizeof (transfer_queue), 1);
314181254a7Smrg   tq->type = type;
315181254a7Smrg   tq->has_id = 0;
316181254a7Smrg   LOCK (&au->lock);
317181254a7Smrg   if (!au->tail)
318181254a7Smrg     au->head = tq;
319181254a7Smrg   else
320181254a7Smrg     au->tail->next = tq;
321181254a7Smrg   au->tail = tq;
322181254a7Smrg   REVOKE_SIGNAL (&(au->emptysignal));
323181254a7Smrg   au->empty = false;
324181254a7Smrg   SIGNAL (&au->work);
325181254a7Smrg   UNLOCK (&au->lock);
326181254a7Smrg }
327181254a7Smrg 
328181254a7Smrg /* Enqueue a CLOSE statement.  */
329181254a7Smrg 
330181254a7Smrg void
enqueue_close(async_unit * au)331181254a7Smrg enqueue_close (async_unit *au)
332181254a7Smrg {
333181254a7Smrg   transfer_queue *tq = calloc (sizeof (transfer_queue), 1);
334181254a7Smrg 
335181254a7Smrg   tq->type = AIO_CLOSE;
336181254a7Smrg   LOCK (&au->lock);
337181254a7Smrg   if (!au->tail)
338181254a7Smrg     au->head = tq;
339181254a7Smrg   else
340181254a7Smrg     au->tail->next = tq;
341181254a7Smrg   au->tail = tq;
342181254a7Smrg   REVOKE_SIGNAL (&(au->emptysignal));
343181254a7Smrg   au->empty = false;
344181254a7Smrg   SIGNAL (&au->work);
345181254a7Smrg   UNLOCK (&au->lock);
346181254a7Smrg }
347181254a7Smrg 
348181254a7Smrg /* The asynchronous unit keeps the currently active PDT around.
349181254a7Smrg    This function changes that to the current one.  */
350181254a7Smrg 
351181254a7Smrg void
enqueue_data_transfer_init(async_unit * au,st_parameter_dt * dt,int read_flag)352181254a7Smrg enqueue_data_transfer_init (async_unit *au, st_parameter_dt *dt, int read_flag)
353181254a7Smrg {
354181254a7Smrg   st_parameter_dt *new = xmalloc (sizeof (st_parameter_dt));
355181254a7Smrg   transfer_queue *tq = xmalloc (sizeof (transfer_queue));
356181254a7Smrg 
357181254a7Smrg   memcpy ((void *) new, (void *) dt, sizeof (st_parameter_dt));
358181254a7Smrg 
359181254a7Smrg   NOTE ("dt->internal_unit_desc = %p", dt->internal_unit_desc);
360181254a7Smrg   NOTE ("common.flags & mask = %d", dt->common.flags & IOPARM_LIBRETURN_MASK);
361181254a7Smrg   tq->next = NULL;
362181254a7Smrg   tq->type = AIO_DATA_TRANSFER_INIT;
363181254a7Smrg   tq->read_flag = read_flag;
364181254a7Smrg   tq->has_id = 0;
365181254a7Smrg   tq->new_pdt = new;
366181254a7Smrg   LOCK (&au->lock);
367181254a7Smrg 
368181254a7Smrg   if (!au->tail)
369181254a7Smrg     au->head = tq;
370181254a7Smrg   else
371181254a7Smrg     au->tail->next = tq;
372181254a7Smrg   au->tail = tq;
373181254a7Smrg   REVOKE_SIGNAL (&(au->emptysignal));
374181254a7Smrg   au->empty = false;
375181254a7Smrg   SIGNAL (&au->work);
376181254a7Smrg   UNLOCK (&au->lock);
377181254a7Smrg }
378181254a7Smrg 
379181254a7Smrg /* Collect the errors that may have happened asynchronously.  Return true if
380181254a7Smrg    an error has been encountered.  */
381181254a7Smrg 
382181254a7Smrg bool
collect_async_errors(st_parameter_common * cmp,async_unit * au)383181254a7Smrg collect_async_errors (st_parameter_common *cmp, async_unit *au)
384181254a7Smrg {
385181254a7Smrg   bool has_error = au->error.has_error;
386181254a7Smrg 
387181254a7Smrg   if (has_error)
388181254a7Smrg     {
389181254a7Smrg       if (generate_error_common (cmp, au->error.family, au->error.message))
390181254a7Smrg 	{
391181254a7Smrg 	  au->error.has_error = 0;
392181254a7Smrg 	  au->error.cmp = NULL;
393181254a7Smrg 	}
394181254a7Smrg       else
395181254a7Smrg 	{
396181254a7Smrg 	  /* The program will exit later.  */
397181254a7Smrg 	  au->error.fatal_error = true;
398181254a7Smrg 	}
399181254a7Smrg     }
400181254a7Smrg   return has_error;
401181254a7Smrg }
402181254a7Smrg 
403181254a7Smrg /* Perform a wait operation on an asynchronous unit with an ID specified,
404181254a7Smrg    which means collecting the errors that may have happened asynchronously.
405181254a7Smrg    Return true if an error has been encountered.  */
406181254a7Smrg 
407181254a7Smrg bool
async_wait_id(st_parameter_common * cmp,async_unit * au,int i)408181254a7Smrg async_wait_id (st_parameter_common *cmp, async_unit *au, int i)
409181254a7Smrg {
410181254a7Smrg   bool ret;
411181254a7Smrg 
412181254a7Smrg   if (au == NULL)
413181254a7Smrg     return false;
414181254a7Smrg 
415181254a7Smrg   if (cmp == NULL)
416181254a7Smrg     cmp = au->error.cmp;
417181254a7Smrg 
418181254a7Smrg   if (au->error.has_error)
419181254a7Smrg     {
420181254a7Smrg       if (i <= au->error.last_good_id)
421181254a7Smrg 	return false;
422181254a7Smrg 
423181254a7Smrg       return collect_async_errors (cmp, au);
424181254a7Smrg     }
425181254a7Smrg 
426181254a7Smrg   LOCK (&au->lock);
427fb8a8121Smrg   if (i > au->id.high)
428fb8a8121Smrg     {
429fb8a8121Smrg       generate_error_common (cmp, LIBERROR_BAD_WAIT_ID, NULL);
430fb8a8121Smrg       UNLOCK (&au->lock);
431fb8a8121Smrg       return true;
432fb8a8121Smrg     }
433fb8a8121Smrg 
434181254a7Smrg   NOTE ("Waiting for id %d", i);
435181254a7Smrg   if (au->id.waiting < i)
436181254a7Smrg     au->id.waiting = i;
437181254a7Smrg   SIGNAL (&(au->work));
438181254a7Smrg   WAIT_SIGNAL_MUTEX (&(au->id.done),
439181254a7Smrg 		     (au->id.low >= au->id.waiting || au->empty), &au->lock);
440181254a7Smrg   LOCK (&au->lock);
441181254a7Smrg   ret = collect_async_errors (cmp, au);
442181254a7Smrg   UNLOCK (&au->lock);
443181254a7Smrg   return ret;
444181254a7Smrg }
445181254a7Smrg 
446181254a7Smrg /* Perform a wait operation an an asynchronous unit without an ID.  */
447181254a7Smrg 
448181254a7Smrg bool
async_wait(st_parameter_common * cmp,async_unit * au)449181254a7Smrg async_wait (st_parameter_common *cmp, async_unit *au)
450181254a7Smrg {
451181254a7Smrg   bool ret;
452181254a7Smrg 
453181254a7Smrg   if (au == NULL)
454181254a7Smrg     return false;
455181254a7Smrg 
456181254a7Smrg   if (cmp == NULL)
457181254a7Smrg     cmp = au->error.cmp;
458181254a7Smrg 
459181254a7Smrg   LOCK (&(au->lock));
460181254a7Smrg   SIGNAL (&(au->work));
461181254a7Smrg 
462181254a7Smrg   if (au->empty)
463181254a7Smrg     {
464181254a7Smrg       ret = collect_async_errors (cmp, au);
465181254a7Smrg       UNLOCK (&au->lock);
466181254a7Smrg       return ret;
467181254a7Smrg     }
468181254a7Smrg 
469181254a7Smrg   WAIT_SIGNAL_MUTEX (&(au->emptysignal), (au->empty), &au->lock);
470181254a7Smrg   ret = collect_async_errors (cmp, au);
471181254a7Smrg   return ret;
472181254a7Smrg }
473181254a7Smrg 
474181254a7Smrg /* Close an asynchronous unit.  */
475181254a7Smrg 
476181254a7Smrg void
async_close(async_unit * au)477181254a7Smrg async_close (async_unit *au)
478181254a7Smrg {
479181254a7Smrg   if (au == NULL)
480181254a7Smrg     return;
481181254a7Smrg 
482181254a7Smrg   NOTE ("Closing async unit");
483181254a7Smrg   enqueue_close (au);
484181254a7Smrg   T_ERROR (__gthread_join, au->thread, NULL);
485181254a7Smrg   free_async_unit (au);
486181254a7Smrg }
487181254a7Smrg 
488181254a7Smrg #else
489181254a7Smrg 
490181254a7Smrg /* Only set u->au to NULL so no async I/O will happen.  */
491181254a7Smrg 
492181254a7Smrg void
init_async_unit(gfc_unit * u)493181254a7Smrg init_async_unit (gfc_unit *u)
494181254a7Smrg {
495181254a7Smrg   u->au = NULL;
496181254a7Smrg   return;
497181254a7Smrg }
498181254a7Smrg 
499181254a7Smrg /* Do-nothing function, which will not be called.  */
500181254a7Smrg 
501181254a7Smrg void
enqueue_transfer(async_unit * au,transfer_args * arg,enum aio_do type)502181254a7Smrg enqueue_transfer (async_unit *au, transfer_args *arg, enum aio_do type)
503181254a7Smrg {
504181254a7Smrg   return;
505181254a7Smrg }
506181254a7Smrg 
507181254a7Smrg /* Do-nothing function, which will not be called.  */
508181254a7Smrg 
509181254a7Smrg int
enqueue_done_id(async_unit * au,enum aio_do type)510181254a7Smrg enqueue_done_id (async_unit *au, enum aio_do type)
511181254a7Smrg {
512181254a7Smrg   return 0;
513181254a7Smrg }
514181254a7Smrg 
515181254a7Smrg /* Do-nothing function, which will not be called.  */
516181254a7Smrg 
517181254a7Smrg void
enqueue_done(async_unit * au,enum aio_do type)518181254a7Smrg enqueue_done (async_unit *au, enum aio_do type)
519181254a7Smrg {
520181254a7Smrg   return;
521181254a7Smrg }
522181254a7Smrg 
523181254a7Smrg /* Do-nothing function, which will not be called.  */
524181254a7Smrg 
525181254a7Smrg void
enqueue_close(async_unit * au)526181254a7Smrg enqueue_close (async_unit *au)
527181254a7Smrg {
528181254a7Smrg   return;
529181254a7Smrg }
530181254a7Smrg 
531181254a7Smrg /* Do-nothing function, which will not be called.  */
532181254a7Smrg 
533181254a7Smrg void
enqueue_data_transfer_init(async_unit * au,st_parameter_dt * dt,int read_flag)534181254a7Smrg enqueue_data_transfer_init (async_unit *au, st_parameter_dt *dt, int read_flag)
535181254a7Smrg {
536181254a7Smrg   return;
537181254a7Smrg }
538181254a7Smrg 
539181254a7Smrg /* Do-nothing function, which will not be called.  */
540181254a7Smrg 
541181254a7Smrg bool
collect_async_errors(st_parameter_common * cmp,async_unit * au)542181254a7Smrg collect_async_errors (st_parameter_common *cmp, async_unit *au)
543181254a7Smrg {
544181254a7Smrg   return false;
545181254a7Smrg }
546181254a7Smrg 
547181254a7Smrg /* Do-nothing function, which will not be called.  */
548181254a7Smrg 
549181254a7Smrg bool
async_wait_id(st_parameter_common * cmp,async_unit * au,int i)550181254a7Smrg async_wait_id (st_parameter_common *cmp, async_unit *au, int i)
551181254a7Smrg {
552181254a7Smrg   return false;
553181254a7Smrg }
554181254a7Smrg 
555181254a7Smrg /* Do-nothing function, which will not be called.  */
556181254a7Smrg 
557181254a7Smrg bool
async_wait(st_parameter_common * cmp,async_unit * au)558181254a7Smrg async_wait (st_parameter_common *cmp, async_unit *au)
559181254a7Smrg {
560181254a7Smrg   return false;
561181254a7Smrg }
562181254a7Smrg 
563181254a7Smrg /* Do-nothing function, which will not be called.  */
564181254a7Smrg 
565181254a7Smrg void
async_close(async_unit * au)566181254a7Smrg async_close (async_unit *au)
567181254a7Smrg {
568181254a7Smrg   return;
569181254a7Smrg }
570181254a7Smrg 
571181254a7Smrg #endif
572