async.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /* Copyright (C) 2018-2022 Free Software Foundation, Inc.
  2. Contributed by Nicolas Koenig
  3. This file is part of the GNU Fortran runtime library (libgfortran).
  4. Libgfortran is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3, or (at your option)
  7. any later version.
  8. Libgfortran is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. Under Section 7 of GPL version 3, you are granted additional
  13. permissions described in the GCC Runtime Library Exception, version
  14. 3.1, as published by the Free Software Foundation.
  15. You should have received a copy of the GNU General Public License and
  16. a copy of the GCC Runtime Library Exception along with this program;
  17. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  18. <http://www.gnu.org/licenses/>. */
  19. #ifndef ASYNC_H
  20. #define ASYNC_H
  21. /* Async I/O will not work on targets which do not support
  22. __gthread_cond_t and __gthread_equal / __gthread_self. Check
  23. this. */
  24. #if defined(__GTHREAD_HAS_COND) && defined(__GTHREADS_CXX0X)
  25. #define ASYNC_IO 1
  26. #else
  27. #define ASYNC_IO 0
  28. #endif
  29. /* Defining DEBUG_ASYNC will enable somewhat verbose debugging
  30. output for async I/O. */
  31. #define DEBUG_ASYNC
  32. #undef DEBUG_ASYNC
  33. #ifdef DEBUG_ASYNC
  34. /* Define this if you want to use ANSI color escape sequences in your
  35. debugging output. */
  36. #define DEBUG_COLOR
  37. #ifdef DEBUG_COLOR
  38. #define MPREFIX "\033[30;46mM:\033[0m "
  39. #define TPREFIX "\033[37;44mT:\033[0m "
  40. #define RPREFIX "\033[37;41mR:\033[0m "
  41. #define DEBUG_RED "\033[31m"
  42. #define DEBUG_ORANGE "\033[33m"
  43. #define DEBUG_GREEN "\033[32m"
  44. #define DEBUG_DARKRED "\033[31;2m"
  45. #define DEBUG_PURPLE "\033[35m"
  46. #define DEBUG_NORM "\033[0m"
  47. #define DEBUG_REVERSE_RED "\033[41;37m"
  48. #define DEBUG_BLUE "\033[34m"
  49. #else
  50. #define MPREFIX "M: "
  51. #define TPREFIX "T: "
  52. #define RPREFIX ""
  53. #define DEBUG_RED ""
  54. #define DEBUG_ORANGE ""
  55. #define DEBUG_GREEN ""
  56. #define DEBUG_DARKRED ""
  57. #define DEBUG_PURPLE ""
  58. #define DEBUG_NORM ""
  59. #define DEBUG_REVERSE_RED ""
  60. #define DEBUG_BLUE ""
  61. #endif
  62. #define DEBUG_PRINTF(...) fprintf (stderr,__VA_ARGS__)
  63. #define IN_DEBUG_QUEUE(mutex) ({ \
  64. __label__ end; \
  65. aio_lock_debug *curr = aio_debug_head; \
  66. while (curr) { \
  67. if (curr->m == mutex) { \
  68. goto end; \
  69. } \
  70. curr = curr->next; \
  71. } \
  72. end:; \
  73. curr; \
  74. })
  75. #define TAIL_DEBUG_QUEUE ({ \
  76. aio_lock_debug *curr = aio_debug_head; \
  77. while (curr && curr->next) { \
  78. curr = curr->next; \
  79. } \
  80. curr; \
  81. })
  82. #define CHECK_LOCK(mutex, status) do { \
  83. aio_lock_debug *curr; \
  84. INTERN_LOCK (&debug_queue_lock); \
  85. if (__gthread_mutex_trylock (mutex)) { \
  86. if ((curr = IN_DEBUG_QUEUE (mutex))) { \
  87. sprintf (status, DEBUG_RED "%s():%d" DEBUG_NORM, curr->func, curr->line); \
  88. } else \
  89. sprintf (status, DEBUG_RED "unknown" DEBUG_NORM); \
  90. } \
  91. else { \
  92. __gthread_mutex_unlock (mutex); \
  93. sprintf (status, DEBUG_GREEN "unlocked" DEBUG_NORM); \
  94. } \
  95. INTERN_UNLOCK (&debug_queue_lock); \
  96. }while (0)
  97. #define T_ERROR(func, ...) do { \
  98. int t_error_temp; \
  99. t_error_temp = func(__VA_ARGS__); \
  100. if (t_error_temp) \
  101. ERROR (t_error_temp, "args: " #__VA_ARGS__ "\n"); \
  102. } while (0)
  103. #define NOTE(str, ...) do{ \
  104. char note_str[200]; \
  105. sprintf (note_str, "%s" DEBUG_PURPLE "NOTE: " DEBUG_NORM str, aio_prefix, ##__VA_ARGS__); \
  106. DEBUG_PRINTF ("%-90s %20s():%-5d\n", note_str, __FUNCTION__, __LINE__); \
  107. }while (0);
  108. #define ERROR(errnum, str, ...) do{ \
  109. char note_str[200]; \
  110. sprintf (note_str, "%s" DEBUG_REVERSE_RED "ERROR:" DEBUG_NORM " [%d] " str, aio_prefix, \
  111. errnum, ##__VA_ARGS__); \
  112. DEBUG_PRINTF ("%-68s %s():%-5d\n", note_str, __FUNCTION__, __LINE__); \
  113. }while (0)
  114. #define MUTEX_DEBUG_ADD(mutex) do { \
  115. aio_lock_debug *n; \
  116. n = malloc (sizeof(aio_lock_debug)); \
  117. n->prev = TAIL_DEBUG_QUEUE; \
  118. if (n->prev) \
  119. n->prev->next = n; \
  120. n->next = NULL; \
  121. n->line = __LINE__; \
  122. n->func = __FUNCTION__; \
  123. n->m = mutex; \
  124. if (!aio_debug_head) { \
  125. aio_debug_head = n; \
  126. } \
  127. } while (0)
  128. #define UNLOCK(mutex) do { \
  129. aio_lock_debug *curr; \
  130. DEBUG_PRINTF ("%s%-75s %20s():%-5d %18p\n", aio_prefix, DEBUG_GREEN "UNLOCK: " DEBUG_NORM #mutex, \
  131. __FUNCTION__, __LINE__, (void *) mutex); \
  132. INTERN_LOCK (&debug_queue_lock); \
  133. curr = IN_DEBUG_QUEUE (mutex); \
  134. if (curr) \
  135. { \
  136. if (curr->prev) \
  137. curr->prev->next = curr->next; \
  138. if (curr->next) { \
  139. curr->next->prev = curr->prev; \
  140. if (curr == aio_debug_head) \
  141. aio_debug_head = curr->next; \
  142. } else { \
  143. if (curr == aio_debug_head) \
  144. aio_debug_head = NULL; \
  145. } \
  146. free (curr); \
  147. } \
  148. INTERN_UNLOCK (&debug_queue_lock); \
  149. INTERN_UNLOCK (mutex); \
  150. }while (0)
  151. #define TRYLOCK(mutex) ({ \
  152. char status[200]; \
  153. int res; \
  154. aio_lock_debug *curr; \
  155. res = __gthread_mutex_trylock (mutex); \
  156. INTERN_LOCK (&debug_queue_lock); \
  157. if (res) { \
  158. if ((curr = IN_DEBUG_QUEUE (mutex))) { \
  159. sprintf (status, DEBUG_RED "%s():%d" DEBUG_NORM, curr->func, curr->line); \
  160. } else \
  161. sprintf (status, DEBUG_RED "unknown" DEBUG_NORM); \
  162. } \
  163. else { \
  164. sprintf (status, DEBUG_GREEN "unlocked" DEBUG_NORM); \
  165. MUTEX_DEBUG_ADD (mutex); \
  166. } \
  167. DEBUG_PRINTF ("%s%-44s prev: %-35s %20s():%-5d %18p\n", aio_prefix, \
  168. DEBUG_DARKRED "TRYLOCK: " DEBUG_NORM #mutex, status, __FUNCTION__, __LINE__, \
  169. (void *) mutex); \
  170. INTERN_UNLOCK (&debug_queue_lock); \
  171. res; \
  172. })
  173. #define LOCK(mutex) do { \
  174. char status[200]; \
  175. CHECK_LOCK (mutex, status); \
  176. DEBUG_PRINTF ("%s%-42s prev: %-35s %20s():%-5d %18p\n", aio_prefix, \
  177. DEBUG_RED "LOCK: " DEBUG_NORM #mutex, status, __FUNCTION__, __LINE__, (void *) mutex); \
  178. INTERN_LOCK (mutex); \
  179. INTERN_LOCK (&debug_queue_lock); \
  180. MUTEX_DEBUG_ADD (mutex); \
  181. INTERN_UNLOCK (&debug_queue_lock); \
  182. DEBUG_PRINTF ("%s" DEBUG_RED "ACQ:" DEBUG_NORM " %-30s %78p\n", aio_prefix, #mutex, mutex); \
  183. } while (0)
  184. #define DEBUG_LINE(...) __VA_ARGS__
  185. #else
  186. #define DEBUG_PRINTF(...) {}
  187. #define CHECK_LOCK(au, mutex, status) {}
  188. #define NOTE(str, ...) {}
  189. #define DEBUG_LINE(...)
  190. #define T_ERROR(func, ...) func(__VA_ARGS__)
  191. #define LOCK(mutex) INTERN_LOCK (mutex)
  192. #define UNLOCK(mutex) INTERN_UNLOCK (mutex)
  193. #define TRYLOCK(mutex) (__gthread_mutex_trylock (mutex))
  194. #endif
  195. #define INTERN_LOCK(mutex) T_ERROR (__gthread_mutex_lock, mutex);
  196. #define INTERN_UNLOCK(mutex) T_ERROR (__gthread_mutex_unlock, mutex);
  197. #if ASYNC_IO
  198. /* au->lock has to be held when calling this macro. */
  199. #define SIGNAL(advcond) do{ \
  200. (advcond)->pending = 1; \
  201. DEBUG_PRINTF ("%s%-75s %20s():%-5d %18p\n", aio_prefix, DEBUG_ORANGE "SIGNAL: " DEBUG_NORM \
  202. #advcond, __FUNCTION__, __LINE__, (void *) advcond); \
  203. T_ERROR (__gthread_cond_broadcast, &(advcond)->signal); \
  204. } while (0)
  205. /* Has to be entered with mutex locked. */
  206. #define WAIT_SIGNAL_MUTEX(advcond, condition, mutex) do{ \
  207. __label__ finish; \
  208. DEBUG_PRINTF ("%s%-75s %20s():%-5d %18p\n", aio_prefix, DEBUG_BLUE "WAITING: " DEBUG_NORM \
  209. #advcond, __FUNCTION__, __LINE__, (void *) advcond); \
  210. if ((advcond)->pending || (condition)) \
  211. goto finish; \
  212. while (1) \
  213. { \
  214. int err_ret = __gthread_cond_wait(&(advcond)->signal, mutex); \
  215. if (err_ret) internal_error (NULL, "WAIT_SIGNAL_MUTEX failed"); \
  216. if (condition) \
  217. { \
  218. DEBUG_PRINTF ("%s%-75s %20s():%-5d %18p\n", aio_prefix, DEBUG_ORANGE \
  219. "REC: " DEBUG_NORM \
  220. #advcond, __FUNCTION__, __LINE__, (void *)advcond); \
  221. break; \
  222. } \
  223. } \
  224. finish: \
  225. (advcond)->pending = 0; \
  226. UNLOCK (mutex); \
  227. } while (0)
  228. /* au->lock has to be held when calling this macro. */
  229. #define REVOKE_SIGNAL(advcond) do{ \
  230. (advcond)->pending = 0; \
  231. } while (0)
  232. #else
  233. #define SIGNAL(advcond) do{} while(0)
  234. #define WAIT_SIGNAL_MUTEX(advcond, condition, mutex) do{} while(0)
  235. #define REVOKE_SIGNAL(advcond) do{} while(0)
  236. #endif
  237. #if ASYNC_IO
  238. DEBUG_LINE (extern __thread const char *aio_prefix);
  239. DEBUG_LINE (typedef struct aio_lock_debug{
  240. __gthread_mutex_t *m;
  241. int line;
  242. const char *func;
  243. struct aio_lock_debug *next;
  244. struct aio_lock_debug *prev;
  245. } aio_lock_debug;)
  246. DEBUG_LINE (extern aio_lock_debug *aio_debug_head;)
  247. DEBUG_LINE (extern __gthread_mutex_t debug_queue_lock;)
  248. /* Thread - local storage of the current unit we are looking at. Needed for
  249. error reporting. */
  250. extern __thread gfc_unit *thread_unit;
  251. #endif
  252. enum aio_do {
  253. AIO_INVALID = 0,
  254. AIO_DATA_TRANSFER_INIT,
  255. AIO_TRANSFER_SCALAR,
  256. AIO_TRANSFER_ARRAY,
  257. AIO_WRITE_DONE,
  258. AIO_READ_DONE,
  259. AIO_CLOSE
  260. };
  261. typedef union transfer_args
  262. {
  263. struct
  264. {
  265. void (*transfer) (struct st_parameter_dt *, bt, void *, int, size_t, size_t);
  266. bt arg_bt;
  267. void *data;
  268. int i;
  269. size_t s1;
  270. size_t s2;
  271. } scalar;
  272. struct
  273. {
  274. gfc_array_char *desc;
  275. int kind;
  276. gfc_charlen_type charlen;
  277. } array;
  278. } transfer_args;
  279. struct adv_cond
  280. {
  281. #if ASYNC_IO
  282. int pending;
  283. __gthread_cond_t signal;
  284. #endif
  285. };
  286. typedef struct async_unit
  287. {
  288. __gthread_mutex_t io_lock; /* Lock for doing actual I/O. */
  289. __gthread_mutex_t lock; /* Lock for manipulating the queue structure. */
  290. bool empty;
  291. struct
  292. {
  293. int waiting;
  294. int low;
  295. int high;
  296. struct adv_cond done;
  297. } id;
  298. #if ASYNC_IO
  299. struct adv_cond work;
  300. struct adv_cond emptysignal;
  301. struct st_parameter_dt *pdt;
  302. pthread_t thread;
  303. struct transfer_queue *head;
  304. struct transfer_queue *tail;
  305. struct {
  306. const char *message;
  307. st_parameter_common *cmp;
  308. bool has_error;
  309. int last_good_id;
  310. int family;
  311. bool fatal_error;
  312. } error;
  313. #endif
  314. } async_unit;
  315. void init_async_unit (gfc_unit *);
  316. internal_proto (init_async_unit);
  317. bool async_wait (st_parameter_common *, async_unit *);
  318. internal_proto (async_wait);
  319. bool async_wait_id (st_parameter_common *, async_unit *, int);
  320. internal_proto (async_wait_id);
  321. bool collect_async_errors (st_parameter_common *, async_unit *);
  322. internal_proto (collect_async_errors);
  323. void async_close (async_unit *);
  324. internal_proto (async_close);
  325. void enqueue_transfer (async_unit * au, transfer_args * arg, enum aio_do);
  326. internal_proto (enqueue_transfer);
  327. void enqueue_done (async_unit *, enum aio_do type);
  328. internal_proto (enqueue_done);
  329. int enqueue_done_id (async_unit *, enum aio_do type);
  330. internal_proto (enqueue_done_id);
  331. void enqueue_init (async_unit *);
  332. internal_proto (enqueue_init);
  333. void enqueue_data_transfer_init (async_unit *, st_parameter_dt *, int);
  334. internal_proto (enqueue_data_transfer_init);
  335. void enqueue_close (async_unit *);
  336. internal_proto (enqueue_close);
  337. #endif