lock.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. /* Locking in multithreaded situations.
  2. Copyright (C) 2005-2020 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, see <https://www.gnu.org/licenses/>. */
  13. /* Written by Bruno Haible <bruno@clisp.org>, 2005.
  14. Based on GCC's gthr-posix.h, gthr-posix95.h. */
  15. #include <config.h>
  16. #include "glthread/lock.h"
  17. /* ========================================================================= */
  18. #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
  19. /* -------------------------- gl_lock_t datatype -------------------------- */
  20. int
  21. glthread_lock_init (gl_lock_t *lock)
  22. {
  23. if (mtx_init (&lock->mutex, mtx_plain) != thrd_success)
  24. return ENOMEM;
  25. lock->init_needed = 0;
  26. return 0;
  27. }
  28. int
  29. glthread_lock_lock (gl_lock_t *lock)
  30. {
  31. if (lock->init_needed)
  32. call_once (&lock->init_once, lock->init_func);
  33. if (mtx_lock (&lock->mutex) != thrd_success)
  34. return EAGAIN;
  35. return 0;
  36. }
  37. int
  38. glthread_lock_unlock (gl_lock_t *lock)
  39. {
  40. if (lock->init_needed)
  41. call_once (&lock->init_once, lock->init_func);
  42. if (mtx_unlock (&lock->mutex) != thrd_success)
  43. return EINVAL;
  44. return 0;
  45. }
  46. int
  47. glthread_lock_destroy (gl_lock_t *lock)
  48. {
  49. if (lock->init_needed)
  50. call_once (&lock->init_once, lock->init_func);
  51. mtx_destroy (&lock->mutex);
  52. return 0;
  53. }
  54. /* ------------------------- gl_rwlock_t datatype ------------------------- */
  55. int
  56. glthread_rwlock_init (gl_rwlock_t *lock)
  57. {
  58. if (mtx_init (&lock->lock, mtx_plain) != thrd_success
  59. || cnd_init (&lock->waiting_readers) != thrd_success
  60. || cnd_init (&lock->waiting_writers) != thrd_success)
  61. return ENOMEM;
  62. lock->waiting_writers_count = 0;
  63. lock->runcount = 0;
  64. lock->init_needed = 0;
  65. return 0;
  66. }
  67. int
  68. glthread_rwlock_rdlock (gl_rwlock_t *lock)
  69. {
  70. if (lock->init_needed)
  71. call_once (&lock->init_once, lock->init_func);
  72. if (mtx_lock (&lock->lock) != thrd_success)
  73. return EAGAIN;
  74. /* Test whether only readers are currently running, and whether the runcount
  75. field will not overflow, and whether no writer is waiting. The latter
  76. condition is because POSIX recommends that "write locks shall take
  77. precedence over read locks", to avoid "writer starvation". */
  78. while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
  79. {
  80. /* This thread has to wait for a while. Enqueue it among the
  81. waiting_readers. */
  82. if (cnd_wait (&lock->waiting_readers, &lock->lock) != thrd_success)
  83. {
  84. mtx_unlock (&lock->lock);
  85. return EINVAL;
  86. }
  87. }
  88. lock->runcount++;
  89. if (mtx_unlock (&lock->lock) != thrd_success)
  90. return EINVAL;
  91. return 0;
  92. }
  93. int
  94. glthread_rwlock_wrlock (gl_rwlock_t *lock)
  95. {
  96. if (lock->init_needed)
  97. call_once (&lock->init_once, lock->init_func);
  98. if (mtx_lock (&lock->lock) != thrd_success)
  99. return EAGAIN;
  100. /* Test whether no readers or writers are currently running. */
  101. while (!(lock->runcount == 0))
  102. {
  103. /* This thread has to wait for a while. Enqueue it among the
  104. waiting_writers. */
  105. lock->waiting_writers_count++;
  106. if (cnd_wait (&lock->waiting_writers, &lock->lock) != thrd_success)
  107. {
  108. lock->waiting_writers_count--;
  109. mtx_unlock (&lock->lock);
  110. return EINVAL;
  111. }
  112. lock->waiting_writers_count--;
  113. }
  114. lock->runcount--; /* runcount becomes -1 */
  115. if (mtx_unlock (&lock->lock) != thrd_success)
  116. return EINVAL;
  117. return 0;
  118. }
  119. int
  120. glthread_rwlock_unlock (gl_rwlock_t *lock)
  121. {
  122. if (lock->init_needed)
  123. call_once (&lock->init_once, lock->init_func);
  124. if (mtx_lock (&lock->lock) != thrd_success)
  125. return EAGAIN;
  126. if (lock->runcount < 0)
  127. {
  128. /* Drop a writer lock. */
  129. if (!(lock->runcount == -1))
  130. {
  131. mtx_unlock (&lock->lock);
  132. return EINVAL;
  133. }
  134. lock->runcount = 0;
  135. }
  136. else
  137. {
  138. /* Drop a reader lock. */
  139. if (!(lock->runcount > 0))
  140. {
  141. mtx_unlock (&lock->lock);
  142. return EINVAL;
  143. }
  144. lock->runcount--;
  145. }
  146. if (lock->runcount == 0)
  147. {
  148. /* POSIX recommends that "write locks shall take precedence over read
  149. locks", to avoid "writer starvation". */
  150. if (lock->waiting_writers_count > 0)
  151. {
  152. /* Wake up one of the waiting writers. */
  153. if (cnd_signal (&lock->waiting_writers) != thrd_success)
  154. {
  155. mtx_unlock (&lock->lock);
  156. return EINVAL;
  157. }
  158. }
  159. else
  160. {
  161. /* Wake up all waiting readers. */
  162. if (cnd_broadcast (&lock->waiting_readers) != thrd_success)
  163. {
  164. mtx_unlock (&lock->lock);
  165. return EINVAL;
  166. }
  167. }
  168. }
  169. if (mtx_unlock (&lock->lock) != thrd_success)
  170. return EINVAL;
  171. return 0;
  172. }
  173. int
  174. glthread_rwlock_destroy (gl_rwlock_t *lock)
  175. {
  176. if (lock->init_needed)
  177. call_once (&lock->init_once, lock->init_func);
  178. mtx_destroy (&lock->lock);
  179. cnd_destroy (&lock->waiting_readers);
  180. cnd_destroy (&lock->waiting_writers);
  181. return 0;
  182. }
  183. /* --------------------- gl_recursive_lock_t datatype --------------------- */
  184. int
  185. glthread_recursive_lock_init (gl_recursive_lock_t *lock)
  186. {
  187. if (mtx_init (&lock->mutex, mtx_plain | mtx_recursive) != thrd_success)
  188. return ENOMEM;
  189. lock->init_needed = 0;
  190. return 0;
  191. }
  192. int
  193. glthread_recursive_lock_lock (gl_recursive_lock_t *lock)
  194. {
  195. if (lock->init_needed)
  196. call_once (&lock->init_once, lock->init_func);
  197. if (mtx_lock (&lock->mutex) != thrd_success)
  198. return EAGAIN;
  199. return 0;
  200. }
  201. int
  202. glthread_recursive_lock_unlock (gl_recursive_lock_t *lock)
  203. {
  204. if (lock->init_needed)
  205. call_once (&lock->init_once, lock->init_func);
  206. if (mtx_unlock (&lock->mutex) != thrd_success)
  207. return EINVAL;
  208. return 0;
  209. }
  210. int
  211. glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
  212. {
  213. if (lock->init_needed)
  214. call_once (&lock->init_once, lock->init_func);
  215. mtx_destroy (&lock->mutex);
  216. return 0;
  217. }
  218. /* -------------------------- gl_once_t datatype -------------------------- */
  219. #endif
  220. /* ========================================================================= */
  221. #if USE_POSIX_THREADS
  222. /* -------------------------- gl_lock_t datatype -------------------------- */
  223. /* ------------------------- gl_rwlock_t datatype ------------------------- */
  224. # if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
  225. # if defined PTHREAD_RWLOCK_INITIALIZER || defined PTHREAD_RWLOCK_INITIALIZER_NP
  226. # if !HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
  227. /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
  228. int
  229. glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock)
  230. {
  231. pthread_rwlockattr_t attributes;
  232. int err;
  233. err = pthread_rwlockattr_init (&attributes);
  234. if (err != 0)
  235. return err;
  236. /* Note: PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP is the only value that
  237. causes the writer to be preferred. PTHREAD_RWLOCK_PREFER_WRITER_NP does not
  238. do this; see
  239. http://man7.org/linux/man-pages/man3/pthread_rwlockattr_setkind_np.3.html */
  240. err = pthread_rwlockattr_setkind_np (&attributes,
  241. PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
  242. if (err == 0)
  243. err = pthread_rwlock_init(lock, &attributes);
  244. /* pthread_rwlockattr_destroy always returns 0. It cannot influence the
  245. return value. */
  246. pthread_rwlockattr_destroy (&attributes);
  247. return err;
  248. }
  249. # endif
  250. # else
  251. int
  252. glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
  253. {
  254. int err;
  255. err = pthread_rwlock_init (&lock->rwlock, NULL);
  256. if (err != 0)
  257. return err;
  258. lock->initialized = 1;
  259. return 0;
  260. }
  261. int
  262. glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
  263. {
  264. if (!lock->initialized)
  265. {
  266. int err;
  267. err = pthread_mutex_lock (&lock->guard);
  268. if (err != 0)
  269. return err;
  270. if (!lock->initialized)
  271. {
  272. err = glthread_rwlock_init_multithreaded (lock);
  273. if (err != 0)
  274. {
  275. pthread_mutex_unlock (&lock->guard);
  276. return err;
  277. }
  278. }
  279. err = pthread_mutex_unlock (&lock->guard);
  280. if (err != 0)
  281. return err;
  282. }
  283. return pthread_rwlock_rdlock (&lock->rwlock);
  284. }
  285. int
  286. glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
  287. {
  288. if (!lock->initialized)
  289. {
  290. int err;
  291. err = pthread_mutex_lock (&lock->guard);
  292. if (err != 0)
  293. return err;
  294. if (!lock->initialized)
  295. {
  296. err = glthread_rwlock_init_multithreaded (lock);
  297. if (err != 0)
  298. {
  299. pthread_mutex_unlock (&lock->guard);
  300. return err;
  301. }
  302. }
  303. err = pthread_mutex_unlock (&lock->guard);
  304. if (err != 0)
  305. return err;
  306. }
  307. return pthread_rwlock_wrlock (&lock->rwlock);
  308. }
  309. int
  310. glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
  311. {
  312. if (!lock->initialized)
  313. return EINVAL;
  314. return pthread_rwlock_unlock (&lock->rwlock);
  315. }
  316. int
  317. glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
  318. {
  319. int err;
  320. if (!lock->initialized)
  321. return EINVAL;
  322. err = pthread_rwlock_destroy (&lock->rwlock);
  323. if (err != 0)
  324. return err;
  325. lock->initialized = 0;
  326. return 0;
  327. }
  328. # endif
  329. # else
  330. int
  331. glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
  332. {
  333. int err;
  334. err = pthread_mutex_init (&lock->lock, NULL);
  335. if (err != 0)
  336. return err;
  337. err = pthread_cond_init (&lock->waiting_readers, NULL);
  338. if (err != 0)
  339. return err;
  340. err = pthread_cond_init (&lock->waiting_writers, NULL);
  341. if (err != 0)
  342. return err;
  343. lock->waiting_writers_count = 0;
  344. lock->runcount = 0;
  345. return 0;
  346. }
  347. int
  348. glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
  349. {
  350. int err;
  351. err = pthread_mutex_lock (&lock->lock);
  352. if (err != 0)
  353. return err;
  354. /* Test whether only readers are currently running, and whether the runcount
  355. field will not overflow, and whether no writer is waiting. The latter
  356. condition is because POSIX recommends that "write locks shall take
  357. precedence over read locks", to avoid "writer starvation". */
  358. while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
  359. {
  360. /* This thread has to wait for a while. Enqueue it among the
  361. waiting_readers. */
  362. err = pthread_cond_wait (&lock->waiting_readers, &lock->lock);
  363. if (err != 0)
  364. {
  365. pthread_mutex_unlock (&lock->lock);
  366. return err;
  367. }
  368. }
  369. lock->runcount++;
  370. return pthread_mutex_unlock (&lock->lock);
  371. }
  372. int
  373. glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
  374. {
  375. int err;
  376. err = pthread_mutex_lock (&lock->lock);
  377. if (err != 0)
  378. return err;
  379. /* Test whether no readers or writers are currently running. */
  380. while (!(lock->runcount == 0))
  381. {
  382. /* This thread has to wait for a while. Enqueue it among the
  383. waiting_writers. */
  384. lock->waiting_writers_count++;
  385. err = pthread_cond_wait (&lock->waiting_writers, &lock->lock);
  386. if (err != 0)
  387. {
  388. lock->waiting_writers_count--;
  389. pthread_mutex_unlock (&lock->lock);
  390. return err;
  391. }
  392. lock->waiting_writers_count--;
  393. }
  394. lock->runcount--; /* runcount becomes -1 */
  395. return pthread_mutex_unlock (&lock->lock);
  396. }
  397. int
  398. glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
  399. {
  400. int err;
  401. err = pthread_mutex_lock (&lock->lock);
  402. if (err != 0)
  403. return err;
  404. if (lock->runcount < 0)
  405. {
  406. /* Drop a writer lock. */
  407. if (!(lock->runcount == -1))
  408. {
  409. pthread_mutex_unlock (&lock->lock);
  410. return EINVAL;
  411. }
  412. lock->runcount = 0;
  413. }
  414. else
  415. {
  416. /* Drop a reader lock. */
  417. if (!(lock->runcount > 0))
  418. {
  419. pthread_mutex_unlock (&lock->lock);
  420. return EINVAL;
  421. }
  422. lock->runcount--;
  423. }
  424. if (lock->runcount == 0)
  425. {
  426. /* POSIX recommends that "write locks shall take precedence over read
  427. locks", to avoid "writer starvation". */
  428. if (lock->waiting_writers_count > 0)
  429. {
  430. /* Wake up one of the waiting writers. */
  431. err = pthread_cond_signal (&lock->waiting_writers);
  432. if (err != 0)
  433. {
  434. pthread_mutex_unlock (&lock->lock);
  435. return err;
  436. }
  437. }
  438. else
  439. {
  440. /* Wake up all waiting readers. */
  441. err = pthread_cond_broadcast (&lock->waiting_readers);
  442. if (err != 0)
  443. {
  444. pthread_mutex_unlock (&lock->lock);
  445. return err;
  446. }
  447. }
  448. }
  449. return pthread_mutex_unlock (&lock->lock);
  450. }
  451. int
  452. glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
  453. {
  454. int err;
  455. err = pthread_mutex_destroy (&lock->lock);
  456. if (err != 0)
  457. return err;
  458. err = pthread_cond_destroy (&lock->waiting_readers);
  459. if (err != 0)
  460. return err;
  461. err = pthread_cond_destroy (&lock->waiting_writers);
  462. if (err != 0)
  463. return err;
  464. return 0;
  465. }
  466. # endif
  467. /* --------------------- gl_recursive_lock_t datatype --------------------- */
  468. # if HAVE_PTHREAD_MUTEX_RECURSIVE
  469. # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
  470. int
  471. glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
  472. {
  473. pthread_mutexattr_t attributes;
  474. int err;
  475. err = pthread_mutexattr_init (&attributes);
  476. if (err != 0)
  477. return err;
  478. err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
  479. if (err != 0)
  480. {
  481. pthread_mutexattr_destroy (&attributes);
  482. return err;
  483. }
  484. err = pthread_mutex_init (lock, &attributes);
  485. if (err != 0)
  486. {
  487. pthread_mutexattr_destroy (&attributes);
  488. return err;
  489. }
  490. err = pthread_mutexattr_destroy (&attributes);
  491. if (err != 0)
  492. return err;
  493. return 0;
  494. }
  495. # else
  496. int
  497. glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
  498. {
  499. pthread_mutexattr_t attributes;
  500. int err;
  501. err = pthread_mutexattr_init (&attributes);
  502. if (err != 0)
  503. return err;
  504. err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
  505. if (err != 0)
  506. {
  507. pthread_mutexattr_destroy (&attributes);
  508. return err;
  509. }
  510. err = pthread_mutex_init (&lock->recmutex, &attributes);
  511. if (err != 0)
  512. {
  513. pthread_mutexattr_destroy (&attributes);
  514. return err;
  515. }
  516. err = pthread_mutexattr_destroy (&attributes);
  517. if (err != 0)
  518. return err;
  519. lock->initialized = 1;
  520. return 0;
  521. }
  522. int
  523. glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
  524. {
  525. if (!lock->initialized)
  526. {
  527. int err;
  528. err = pthread_mutex_lock (&lock->guard);
  529. if (err != 0)
  530. return err;
  531. if (!lock->initialized)
  532. {
  533. err = glthread_recursive_lock_init_multithreaded (lock);
  534. if (err != 0)
  535. {
  536. pthread_mutex_unlock (&lock->guard);
  537. return err;
  538. }
  539. }
  540. err = pthread_mutex_unlock (&lock->guard);
  541. if (err != 0)
  542. return err;
  543. }
  544. return pthread_mutex_lock (&lock->recmutex);
  545. }
  546. int
  547. glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
  548. {
  549. if (!lock->initialized)
  550. return EINVAL;
  551. return pthread_mutex_unlock (&lock->recmutex);
  552. }
  553. int
  554. glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
  555. {
  556. int err;
  557. if (!lock->initialized)
  558. return EINVAL;
  559. err = pthread_mutex_destroy (&lock->recmutex);
  560. if (err != 0)
  561. return err;
  562. lock->initialized = 0;
  563. return 0;
  564. }
  565. # endif
  566. # else
  567. int
  568. glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
  569. {
  570. int err;
  571. err = pthread_mutex_init (&lock->mutex, NULL);
  572. if (err != 0)
  573. return err;
  574. lock->owner = (pthread_t) 0;
  575. lock->depth = 0;
  576. return 0;
  577. }
  578. int
  579. glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
  580. {
  581. pthread_t self = pthread_self ();
  582. if (lock->owner != self)
  583. {
  584. int err;
  585. err = pthread_mutex_lock (&lock->mutex);
  586. if (err != 0)
  587. return err;
  588. lock->owner = self;
  589. }
  590. if (++(lock->depth) == 0) /* wraparound? */
  591. {
  592. lock->depth--;
  593. return EAGAIN;
  594. }
  595. return 0;
  596. }
  597. int
  598. glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
  599. {
  600. if (lock->owner != pthread_self ())
  601. return EPERM;
  602. if (lock->depth == 0)
  603. return EINVAL;
  604. if (--(lock->depth) == 0)
  605. {
  606. lock->owner = (pthread_t) 0;
  607. return pthread_mutex_unlock (&lock->mutex);
  608. }
  609. else
  610. return 0;
  611. }
  612. int
  613. glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
  614. {
  615. if (lock->owner != (pthread_t) 0)
  616. return EBUSY;
  617. return pthread_mutex_destroy (&lock->mutex);
  618. }
  619. # endif
  620. /* -------------------------- gl_once_t datatype -------------------------- */
  621. static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
  622. int
  623. glthread_once_singlethreaded (pthread_once_t *once_control)
  624. {
  625. /* We don't know whether pthread_once_t is an integer type, a floating-point
  626. type, a pointer type, or a structure type. */
  627. char *firstbyte = (char *)once_control;
  628. if (*firstbyte == *(const char *)&fresh_once)
  629. {
  630. /* First time use of once_control. Invert the first byte. */
  631. *firstbyte = ~ *(const char *)&fresh_once;
  632. return 1;
  633. }
  634. else
  635. return 0;
  636. }
  637. # if !(PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK)
  638. int
  639. glthread_once_multithreaded (pthread_once_t *once_control,
  640. void (*init_function) (void))
  641. {
  642. int err = pthread_once (once_control, init_function);
  643. if (err == ENOSYS)
  644. {
  645. /* This happens on FreeBSD 11: The pthread_once function in libc returns
  646. ENOSYS. */
  647. if (glthread_once_singlethreaded (once_control))
  648. init_function ();
  649. return 0;
  650. }
  651. return err;
  652. }
  653. # endif
  654. #endif
  655. /* ========================================================================= */
  656. #if USE_WINDOWS_THREADS
  657. #endif
  658. /* ========================================================================= */