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