Home | History | Annotate | Line # | Download | only in io
async.h revision 1.1.1.4
      1 /* Copyright (C) 2018-2024 Free Software Foundation, Inc.
      2    Contributed by Nicolas Koenig
      3 
      4    This file is part of the GNU Fortran runtime library (libgfortran).
      5 
      6    Libgfortran is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by
      8    the Free Software Foundation; either version 3, or (at your option)
      9    any later version.
     10 
     11    Libgfortran is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14    GNU General Public License for more details.
     15 
     16    Under Section 7 of GPL version 3, you are granted additional
     17    permissions described in the GCC Runtime Library Exception, version
     18    3.1, as published by the Free Software Foundation.
     19 
     20    You should have received a copy of the GNU General Public License and
     21    a copy of the GCC Runtime Library Exception along with this program;
     22    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23    <http://www.gnu.org/licenses/>.  */
     24 
     25 #ifndef ASYNC_H
     26 #define ASYNC_H
     27 
     28 /* Async I/O will not work on targets which do not support
     29    __gthread_cond_t and __gthread_equal / __gthread_self.  Check
     30    this.  */
     31 
     32 #if defined(__GTHREAD_HAS_COND) && defined(__GTHREADS_CXX0X)
     33 #define ASYNC_IO 1
     34 #else
     35 #define ASYNC_IO 0
     36 #endif
     37 
     38 /* Defining DEBUG_ASYNC will enable somewhat verbose debugging
     39    output for async I/O.  */
     40 
     41 #define DEBUG_ASYNC
     42 #undef DEBUG_ASYNC
     43 
     44 #ifdef DEBUG_ASYNC
     45 
     46 /* Define this if you want to use ANSI color escape sequences in your
     47    debugging output.  */
     48 
     49 #define DEBUG_COLOR
     50 
     51 #ifdef DEBUG_COLOR
     52 #define MPREFIX "\033[30;46mM:\033[0m "
     53 #define TPREFIX "\033[37;44mT:\033[0m "
     54 #define RPREFIX "\033[37;41mR:\033[0m "
     55 #define DEBUG_RED "\033[31m"
     56 #define DEBUG_ORANGE "\033[33m"
     57 #define DEBUG_GREEN "\033[32m"
     58 #define DEBUG_DARKRED "\033[31;2m"
     59 #define DEBUG_PURPLE "\033[35m"
     60 #define DEBUG_NORM "\033[0m"
     61 #define DEBUG_REVERSE_RED "\033[41;37m"
     62 #define DEBUG_BLUE "\033[34m"
     63 
     64 #else
     65 
     66 #define MPREFIX "M: "
     67 #define TPREFIX "T: "
     68 #define RPREFIX ""
     69 #define DEBUG_RED ""
     70 #define DEBUG_ORANGE ""
     71 #define DEBUG_GREEN ""
     72 #define DEBUG_DARKRED ""
     73 #define DEBUG_PURPLE ""
     74 #define DEBUG_NORM ""
     75 #define DEBUG_REVERSE_RED ""
     76 #define DEBUG_BLUE ""
     77 
     78 #endif
     79 
     80 #define DEBUG_PRINTF(...) fprintf (stderr,__VA_ARGS__)
     81 
     82 #define IN_DEBUG_QUEUE(mutex) ({		\
     83       __label__ end;				\
     84       aio_lock_debug *curr = aio_debug_head;	\
     85       while (curr) {				\
     86 	if (curr->m == mutex) {			\
     87 	  goto end;				\
     88 	}					\
     89 	curr = curr->next;			\
     90       }						\
     91     end:;					\
     92       curr;					\
     93     })
     94 
     95 #define TAIL_DEBUG_QUEUE ({			\
     96       aio_lock_debug *curr = aio_debug_head;	\
     97       while (curr && curr->next) {		\
     98 	curr = curr->next;			\
     99       }						\
    100       curr;					\
    101     })
    102 
    103 #define CHECK_LOCK(mutex, status) do {					\
    104     aio_lock_debug *curr;						\
    105     INTERN_LOCK (&debug_queue_lock);					\
    106     if (__gthread_mutex_trylock (mutex)) {				\
    107       if ((curr = IN_DEBUG_QUEUE (mutex))) {				\
    108 	sprintf (status, DEBUG_RED "%s():%d" DEBUG_NORM, curr->func, curr->line); \
    109       } else								\
    110 	sprintf (status, DEBUG_RED "unknown" DEBUG_NORM);			\
    111     }									\
    112     else {								\
    113       __gthread_mutex_unlock (mutex);					\
    114       sprintf (status, DEBUG_GREEN "unlocked" DEBUG_NORM);			\
    115     }									\
    116     INTERN_UNLOCK (&debug_queue_lock);					\
    117   }while (0)
    118 
    119 #define T_ERROR(func, ...) do {				\
    120     int t_error_temp;					\
    121     t_error_temp = func(__VA_ARGS__);			\
    122     if (t_error_temp)					\
    123       ERROR (t_error_temp, "args: " #__VA_ARGS__ "\n");	\
    124   } while (0)
    125 
    126 #define NOTE(str, ...) do{						\
    127     char note_str[200];							\
    128     sprintf (note_str, "%s" DEBUG_PURPLE "NOTE: " DEBUG_NORM str, aio_prefix, ##__VA_ARGS__); \
    129     DEBUG_PRINTF ("%-90s %20s():%-5d\n", note_str, __FUNCTION__, __LINE__); \
    130   }while (0);
    131 
    132 #define ERROR(errnum, str, ...) do{					\
    133     char note_str[200];							\
    134     sprintf (note_str, "%s" DEBUG_REVERSE_RED "ERROR:" DEBUG_NORM " [%d] " str, aio_prefix, \
    135 	    errnum, ##__VA_ARGS__);					\
    136     DEBUG_PRINTF ("%-68s %s():%-5d\n", note_str, __FUNCTION__, __LINE__);	\
    137   }while (0)
    138 
    139 #define MUTEX_DEBUG_ADD(mutex) do {		\
    140     aio_lock_debug *n;				\
    141     n = malloc (sizeof(aio_lock_debug));	\
    142     n->prev = TAIL_DEBUG_QUEUE;			\
    143     if (n->prev)				\
    144       n->prev->next = n;			\
    145     n->next = NULL;				\
    146     n->line = __LINE__;				\
    147     n->func = __FUNCTION__;			\
    148     n->m = mutex;				\
    149     if (!aio_debug_head) {			\
    150       aio_debug_head = n;			\
    151     }						\
    152   } while (0)
    153 
    154 #define UNLOCK(mutex) do {						\
    155     aio_lock_debug *curr;						\
    156     DEBUG_PRINTF ("%s%-75s %20s():%-5d %18p\n", aio_prefix, DEBUG_GREEN "UNLOCK: " DEBUG_NORM #mutex, \
    157 		 __FUNCTION__, __LINE__, (void *) mutex);		\
    158     INTERN_LOCK (&debug_queue_lock);					\
    159     curr = IN_DEBUG_QUEUE (mutex);					\
    160     if (curr)								\
    161       {									\
    162 	if (curr->prev)							\
    163 	  curr->prev->next = curr->next;				\
    164 	if (curr->next) {						\
    165 	  curr->next->prev = curr->prev;				\
    166 	  if (curr == aio_debug_head)					\
    167 	    aio_debug_head = curr->next;				\
    168 	} else {							\
    169 	  if (curr == aio_debug_head)					\
    170 	    aio_debug_head = NULL;					\
    171 	}								\
    172 	free (curr);							\
    173       }									\
    174     INTERN_UNLOCK (&debug_queue_lock);					\
    175     INTERN_UNLOCK (mutex);						\
    176   }while (0)
    177 
    178 #define TRYLOCK(mutex) ({						\
    179 			 char status[200];				\
    180 			 int res;					\
    181 			 aio_lock_debug *curr;				\
    182 			 res = __gthread_mutex_trylock (mutex);		\
    183 			 INTERN_LOCK (&debug_queue_lock);		\
    184 			 if (res) {					\
    185 			   if ((curr = IN_DEBUG_QUEUE (mutex))) {	\
    186 			     sprintf (status, DEBUG_RED "%s():%d" DEBUG_NORM, curr->func, curr->line);	\
    187 			   } else					\
    188 			     sprintf (status, DEBUG_RED "unknown" DEBUG_NORM);	\
    189 			 }						\
    190 			 else {						\
    191 			   sprintf (status, DEBUG_GREEN "unlocked" DEBUG_NORM);	\
    192 			   MUTEX_DEBUG_ADD (mutex);			\
    193 			 }						\
    194 			 DEBUG_PRINTF ("%s%-44s prev: %-35s %20s():%-5d %18p\n", aio_prefix, \
    195 				      DEBUG_DARKRED "TRYLOCK: " DEBUG_NORM #mutex, status, __FUNCTION__, __LINE__, \
    196 				      (void *) mutex);			\
    197 			 INTERN_UNLOCK (&debug_queue_lock);		\
    198 			 res;						\
    199     })
    200 
    201 #define LOCK(mutex) do {						\
    202     char status[200];							\
    203     CHECK_LOCK (mutex, status);						\
    204     DEBUG_PRINTF ("%s%-42s prev: %-35s %20s():%-5d %18p\n", aio_prefix,	\
    205 		 DEBUG_RED "LOCK: " DEBUG_NORM #mutex, status, __FUNCTION__, __LINE__, (void *) mutex); \
    206     INTERN_LOCK (mutex);							\
    207     INTERN_LOCK (&debug_queue_lock);					\
    208     MUTEX_DEBUG_ADD (mutex);						\
    209     INTERN_UNLOCK (&debug_queue_lock);					\
    210     DEBUG_PRINTF ("%s" DEBUG_RED "ACQ:" DEBUG_NORM " %-30s %78p\n", aio_prefix, #mutex, mutex); \
    211   } while (0)
    212 
    213 #ifdef __GTHREAD_RWLOCK_INIT
    214 #define RWLOCK_DEBUG_ADD(rwlock) do {		\
    215     aio_rwlock_debug *n;				\
    216     n = xmalloc (sizeof (aio_rwlock_debug));	\
    217     n->prev = TAIL_RWLOCK_DEBUG_QUEUE;			\
    218     if (n->prev)				\
    219       n->prev->next = n;			\
    220     n->next = NULL;				\
    221     n->line = __LINE__;				\
    222     n->func = __FUNCTION__;			\
    223     n->rw = rwlock;				\
    224     if (!aio_rwlock_debug_head) {			\
    225       aio_rwlock_debug_head = n;			\
    226     }						\
    227   } while (0)
    228 
    229 #define CHECK_RDLOCK(rwlock, status) do {					\
    230     aio_rwlock_debug *curr;						\
    231     INTERN_WRLOCK (&debug_queue_rwlock);					\
    232     if (__gthread_rwlock_tryrdlock (rwlock)) {				\
    233       if ((curr = IN_RWLOCK_DEBUG_QUEUE (rwlock))) {				\
    234 	sprintf (status, DEBUG_RED "%s():%d" DEBUG_NORM, curr->func, curr->line); \
    235       } else								\
    236 	sprintf (status, DEBUG_RED "unknown" DEBUG_NORM);			\
    237     }									\
    238     else {								\
    239       __gthread_rwlock_unlock (rwlock);					\
    240       sprintf (status, DEBUG_GREEN "rwunlocked" DEBUG_NORM);			\
    241     }									\
    242     INTERN_RWUNLOCK (&debug_queue_rwlock);					\
    243   }while (0)
    244 
    245 #define CHECK_WRLOCK(rwlock, status) do {					\
    246     aio_rwlock_debug *curr;						\
    247     INTERN_WRLOCK (&debug_queue_rwlock);					\
    248     if (__gthread_rwlock_trywrlock (rwlock)) {				\
    249       if ((curr = IN_RWLOCK_DEBUG_QUEUE (rwlock))) {				\
    250 	sprintf (status, DEBUG_RED "%s():%d" DEBUG_NORM, curr->func, curr->line); \
    251       } else								\
    252 	sprintf (status, DEBUG_RED "unknown" DEBUG_NORM);			\
    253     }									\
    254     else {								\
    255       __gthread_rwlock_unlock (rwlock);					\
    256       sprintf (status, DEBUG_GREEN "rwunlocked" DEBUG_NORM);			\
    257     }									\
    258     INTERN_RWUNLOCK (&debug_queue_rwlock);					\
    259   }while (0)
    260 
    261 #define TAIL_RWLOCK_DEBUG_QUEUE ({			\
    262       aio_rwlock_debug *curr = aio_rwlock_debug_head;	\
    263       while (curr && curr->next) {		\
    264 	curr = curr->next;			\
    265       }						\
    266       curr;					\
    267     })
    268 
    269 #define IN_RWLOCK_DEBUG_QUEUE(rwlock) ({		\
    270       __label__ end;				\
    271       aio_rwlock_debug *curr = aio_rwlock_debug_head;	\
    272       while (curr) {				\
    273 	if (curr->rw == rwlock) {			\
    274 	  goto end;				\
    275 	}					\
    276 	curr = curr->next;			\
    277       }						\
    278     end:;					\
    279       curr;					\
    280     })
    281 
    282 #define RDLOCK(rwlock) do {						\
    283     char status[200];							\
    284     CHECK_RDLOCK (rwlock, status);						\
    285     DEBUG_PRINTF ("%s%-42s prev: %-35s %20s():%-5d %18p\n", aio_prefix,	\
    286 		 DEBUG_RED "RDLOCK: " DEBUG_NORM #rwlock, status, __FUNCTION__, __LINE__, (void *) rwlock); \
    287     INTERN_RDLOCK (rwlock);							\
    288     INTERN_WRLOCK (&debug_queue_rwlock);					\
    289     RWLOCK_DEBUG_ADD (rwlock);						\
    290     INTERN_RWUNLOCK (&debug_queue_rwlock);					\
    291     DEBUG_PRINTF ("%s" DEBUG_RED "ACQ:" DEBUG_NORM " %-30s %78p\n", aio_prefix, #rwlock, rwlock); \
    292   } while (0)
    293 
    294 #define WRLOCK(rwlock) do {						\
    295     char status[200];							\
    296     CHECK_WRLOCK (rwlock, status);						\
    297     DEBUG_PRINTF ("%s%-42s prev: %-35s %20s():%-5d %18p\n", aio_prefix,	\
    298 		 DEBUG_RED "WRLOCK: " DEBUG_NORM #rwlock, status, __FUNCTION__, __LINE__, (void *) rwlock); \
    299     INTERN_WRLOCK (rwlock);							\
    300     INTERN_WRLOCK (&debug_queue_rwlock);					\
    301     RWLOCK_DEBUG_ADD (rwlock);						\
    302     INTERN_RWUNLOCK (&debug_queue_rwlock);					\
    303     DEBUG_PRINTF ("%s" DEBUG_RED "ACQ:" DEBUG_NORM " %-30s %78p\n", aio_prefix, #rwlock, rwlock); \
    304   } while (0)
    305 
    306 #define RWUNLOCK(rwlock) do {						\
    307     aio_rwlock_debug *curr;						\
    308     DEBUG_PRINTF ("%s%-75s %20s():%-5d %18p\n", aio_prefix, DEBUG_GREEN "RWUNLOCK: " DEBUG_NORM #rwlock, \
    309 		 __FUNCTION__, __LINE__, (void *) rwlock);		\
    310     INTERN_WRLOCK (&debug_queue_rwlock);					\
    311     curr = IN_RWLOCK_DEBUG_QUEUE (rwlock);					\
    312     if (curr)								\
    313       {									\
    314 	if (curr->prev)							\
    315 	  curr->prev->next = curr->next;				\
    316 	if (curr->next) {						\
    317 	  curr->next->prev = curr->prev;				\
    318 	  if (curr == aio_rwlock_debug_head)					\
    319 	    aio_rwlock_debug_head = curr->next;				\
    320 	} else {							\
    321 	  if (curr == aio_rwlock_debug_head)					\
    322 	    aio_rwlock_debug_head = NULL;					\
    323 	}								\
    324 	free (curr);							\
    325       }									\
    326     INTERN_RWUNLOCK (&debug_queue_rwlock);					\
    327     INTERN_RWUNLOCK (rwlock);						\
    328   } while (0)
    329 
    330 #define RD_TO_WRLOCK(rwlock)	\
    331   RWUNLOCK (rwlock);	\
    332   WRLOCK (rwlock);
    333 #endif
    334 
    335 #define DEBUG_LINE(...) __VA_ARGS__
    336 
    337 #else
    338 #define DEBUG_PRINTF(...) {}
    339 #define CHECK_LOCK(au, mutex, status) {}
    340 #define NOTE(str, ...) {}
    341 #define DEBUG_LINE(...)
    342 #define T_ERROR(func, ...) func(__VA_ARGS__)
    343 #define LOCK(mutex) INTERN_LOCK (mutex)
    344 #define UNLOCK(mutex) INTERN_UNLOCK (mutex)
    345 #define TRYLOCK(mutex) (__gthread_mutex_trylock (mutex))
    346 #ifdef __GTHREAD_RWLOCK_INIT
    347 #define RDLOCK(rwlock) INTERN_RDLOCK (rwlock)
    348 #define WRLOCK(rwlock) INTERN_WRLOCK (rwlock)
    349 #define RWUNLOCK(rwlock) INTERN_RWUNLOCK (rwlock)
    350 #define RD_TO_WRLOCK(rwlock)	\
    351   RWUNLOCK (rwlock);	\
    352   WRLOCK (rwlock);
    353 #endif
    354 #endif
    355 
    356 #ifndef __GTHREAD_RWLOCK_INIT
    357 #define RDLOCK(rwlock) LOCK (rwlock)
    358 #define WRLOCK(rwlock) LOCK (rwlock)
    359 #define RWUNLOCK(rwlock) UNLOCK (rwlock)
    360 #define RD_TO_WRLOCK(rwlock) do {} while (0)
    361 #endif
    362 
    363 #define INTERN_LOCK(mutex) T_ERROR (__gthread_mutex_lock, mutex);
    364 
    365 #define INTERN_UNLOCK(mutex) T_ERROR (__gthread_mutex_unlock, mutex);
    366 
    367 #define INTERN_RDLOCK(rwlock) T_ERROR (__gthread_rwlock_rdlock, rwlock)
    368 #define INTERN_WRLOCK(rwlock) T_ERROR (__gthread_rwlock_wrlock, rwlock)
    369 #define INTERN_RWUNLOCK(rwlock) T_ERROR (__gthread_rwlock_unlock, rwlock)
    370 
    371 #if ASYNC_IO
    372 
    373 /* au->lock has to be held when calling this macro.  */
    374 
    375 #define SIGNAL(advcond) do{						\
    376     (advcond)->pending = 1;						\
    377     DEBUG_PRINTF ("%s%-75s %20s():%-5d %18p\n", aio_prefix, DEBUG_ORANGE "SIGNAL: " DEBUG_NORM \
    378 		 #advcond, __FUNCTION__, __LINE__, (void *) advcond);	\
    379     T_ERROR (__gthread_cond_broadcast, &(advcond)->signal);			\
    380   } while (0)
    381 
    382 /* Has to be entered with mutex locked.  */
    383 
    384 #define WAIT_SIGNAL_MUTEX(advcond, condition, mutex) do{		\
    385     __label__ finish;		       					\
    386     DEBUG_PRINTF ("%s%-75s %20s():%-5d %18p\n", aio_prefix, DEBUG_BLUE "WAITING: " DEBUG_NORM \
    387 		 #advcond, __FUNCTION__, __LINE__, (void *) advcond);	\
    388     if ((advcond)->pending || (condition))				\
    389       goto finish;							\
    390     while (1)								\
    391       {									\
    392 	int err_ret = __gthread_cond_wait(&(advcond)->signal, mutex);	\
    393 	if (err_ret) internal_error (NULL, "WAIT_SIGNAL_MUTEX failed");	\
    394 	if (condition)							\
    395 	  {								\
    396 	    DEBUG_PRINTF ("%s%-75s %20s():%-5d %18p\n", aio_prefix, DEBUG_ORANGE \
    397 			  "REC: " DEBUG_NORM				\
    398 			  #advcond,  __FUNCTION__, __LINE__, (void *)advcond); \
    399 	    break;				      			\
    400 	  }								\
    401       }									\
    402   finish:								\
    403     (advcond)->pending = 0;						\
    404     UNLOCK (mutex);							\
    405   } while (0)
    406 
    407 /* au->lock has to be held when calling this macro.  */
    408 
    409 #define REVOKE_SIGNAL(advcond) do{		\
    410     (advcond)->pending = 0;			\
    411   } while (0)
    412 
    413 #else
    414 
    415 #define SIGNAL(advcond) do{} while(0)
    416 #define WAIT_SIGNAL_MUTEX(advcond, condition, mutex) do{} while(0)
    417 #define REVOKE_SIGNAL(advcond) do{} while(0)
    418 
    419 #endif
    420 
    421 #if ASYNC_IO
    422 DEBUG_LINE (extern __thread const char *aio_prefix);
    423 
    424 DEBUG_LINE (typedef struct aio_lock_debug{
    425   __gthread_mutex_t *m;
    426   int line;
    427   const char *func;
    428   struct aio_lock_debug *next;
    429   struct aio_lock_debug *prev;
    430 } aio_lock_debug;)
    431 
    432 DEBUG_LINE (typedef struct aio_rwlock_debug{
    433   __gthread_rwlock_t *rw;
    434   int line;
    435   const char *func;
    436   struct aio_rwlock_debug *next;
    437   struct aio_rwlock_debug *prev;
    438 } aio_rwlock_debug;)
    439 
    440 DEBUG_LINE (extern aio_lock_debug *aio_debug_head;)
    441 DEBUG_LINE (extern __gthread_mutex_t debug_queue_lock;)
    442 DEBUG_LINE (extern aio_rwlock_debug *aio_rwlock_debug_head;)
    443 DEBUG_LINE (extern __gthread_rwlock_t debug_queue_rwlock;)
    444 
    445 /* Thread - local storage of the current unit we are looking at. Needed for
    446    error reporting.  */
    447 
    448 extern __thread gfc_unit *thread_unit;
    449 #endif
    450 
    451 enum aio_do {
    452   AIO_INVALID = 0,
    453   AIO_DATA_TRANSFER_INIT,
    454   AIO_TRANSFER_SCALAR,
    455   AIO_TRANSFER_ARRAY,
    456   AIO_WRITE_DONE,
    457   AIO_READ_DONE,
    458   AIO_CLOSE
    459 };
    460 
    461 typedef union transfer_args
    462 {
    463   struct
    464   {
    465     void (*transfer) (struct st_parameter_dt *, bt, void *, int, size_t, size_t);
    466     bt arg_bt;
    467     void *data;
    468     int i;
    469     size_t s1;
    470     size_t s2;
    471   } scalar;
    472   struct
    473   {
    474     gfc_array_char *desc;
    475     int kind;
    476     gfc_charlen_type charlen;
    477   } array;
    478 } transfer_args;
    479 
    480 struct adv_cond
    481 {
    482 #if ASYNC_IO
    483   int pending;
    484   __gthread_cond_t signal;
    485 #endif
    486 };
    487 
    488 typedef struct async_unit
    489 {
    490   __gthread_mutex_t io_lock;   /* Lock for doing actual I/O. */
    491   __gthread_mutex_t lock;      /* Lock for manipulating the queue structure.  */
    492   bool empty;
    493   struct
    494   {
    495     int waiting;
    496     int low;
    497     int high;
    498     struct adv_cond done;
    499   } id;
    500 
    501 #if ASYNC_IO
    502   struct adv_cond work;
    503   struct adv_cond emptysignal;
    504   struct st_parameter_dt *pdt;
    505   __gthread_t thread;
    506   struct transfer_queue *head;
    507   struct transfer_queue *tail;
    508 
    509   struct {
    510     const char *message;
    511     st_parameter_common *cmp;
    512     bool has_error;
    513     int last_good_id;
    514     int family;
    515     bool fatal_error;
    516   } error;
    517 #endif
    518 } async_unit;
    519 
    520 void init_async_unit (gfc_unit *);
    521 internal_proto (init_async_unit);
    522 
    523 bool async_wait (st_parameter_common *, async_unit *);
    524 internal_proto (async_wait);
    525 
    526 bool async_wait_id (st_parameter_common *, async_unit *, int);
    527 internal_proto (async_wait_id);
    528 
    529 bool collect_async_errors (st_parameter_common *, async_unit *);
    530 internal_proto (collect_async_errors);
    531 
    532 void async_close (async_unit *);
    533 internal_proto (async_close);
    534 
    535 void enqueue_transfer (async_unit * au, transfer_args * arg, enum aio_do);
    536 internal_proto (enqueue_transfer);
    537 
    538 void enqueue_done (async_unit *, enum aio_do type);
    539 internal_proto (enqueue_done);
    540 
    541 int enqueue_done_id (async_unit *, enum aio_do type);
    542 internal_proto (enqueue_done_id);
    543 
    544 void enqueue_init (async_unit *);
    545 internal_proto (enqueue_init);
    546 
    547 void enqueue_data_transfer_init (async_unit *, st_parameter_dt *, int);
    548 internal_proto (enqueue_data_transfer_init);
    549 
    550 void enqueue_close (async_unit *);
    551 internal_proto (enqueue_close);
    552 
    553 #endif
    554