mbtowc-lock.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /* Return the internal lock used by mbrtowc and mbrtoc32.
  2. Copyright (C) 2019-2023 Free Software Foundation, Inc.
  3. This file is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as
  5. published by the Free Software Foundation; either version 2.1 of the
  6. License, or (at your option) any later version.
  7. This file 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 Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. /* Written by Bruno Haible <bruno@clisp.org>, 2019-2020. */
  14. #include <config.h>
  15. /* When it is known that the gl_get_mbtowc_lock function is defined
  16. by a dependency library, it should not be defined here. */
  17. #if OMIT_MBTOWC_LOCK
  18. /* This declaration is solely to ensure that after preprocessing
  19. this file is never empty. */
  20. typedef int dummy;
  21. #else
  22. /* This file defines the internal lock used by mbrtowc and mbrtoc32.
  23. It is a separate compilation unit, so that only one copy of it is
  24. present when linking statically. */
  25. /* Prohibit renaming this symbol. */
  26. # undef gl_get_mbtowc_lock
  27. /* Macro for exporting a symbol (function, not variable) defined in this file,
  28. when compiled into a shared library. */
  29. # ifndef DLL_EXPORTED
  30. # if HAVE_VISIBILITY
  31. /* Override the effect of the compiler option '-fvisibility=hidden'. */
  32. # define DLL_EXPORTED __attribute__((__visibility__("default")))
  33. # elif defined _WIN32 || defined __CYGWIN__
  34. # define DLL_EXPORTED __declspec(dllexport)
  35. # else
  36. # define DLL_EXPORTED
  37. # endif
  38. # endif
  39. # if defined _WIN32 && !defined __CYGWIN__
  40. # define WIN32_LEAN_AND_MEAN /* avoid including junk */
  41. # include <windows.h>
  42. # include "windows-initguard.h"
  43. /* The return type is a 'CRITICAL_SECTION *', not a 'glwthread_mutex_t *',
  44. because the latter is not guaranteed to be a stable ABI in the future. */
  45. /* Make sure the function gets exported from DLLs. */
  46. DLL_EXPORTED CRITICAL_SECTION *gl_get_mbtowc_lock (void);
  47. static glwthread_initguard_t guard = GLWTHREAD_INITGUARD_INIT;
  48. static CRITICAL_SECTION lock;
  49. /* Returns the internal lock used by mbrtowc and mbrtoc32. */
  50. CRITICAL_SECTION *
  51. gl_get_mbtowc_lock (void)
  52. {
  53. if (!guard.done)
  54. {
  55. if (InterlockedIncrement (&guard.started) == 0)
  56. {
  57. /* This thread is the first one to need the lock. Initialize it. */
  58. InitializeCriticalSection (&lock);
  59. guard.done = 1;
  60. }
  61. else
  62. {
  63. /* Don't let guard.started grow and wrap around. */
  64. InterlockedDecrement (&guard.started);
  65. /* Yield the CPU while waiting for another thread to finish
  66. initializing this mutex. */
  67. while (!guard.done)
  68. Sleep (0);
  69. }
  70. }
  71. return &lock;
  72. }
  73. # elif HAVE_PTHREAD_API
  74. # include <pthread.h>
  75. static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  76. /* Make sure the function gets exported from shared libraries. */
  77. DLL_EXPORTED pthread_mutex_t *gl_get_mbtowc_lock (void);
  78. /* Returns the internal lock used by mbrtowc and mbrtoc32. */
  79. pthread_mutex_t *
  80. gl_get_mbtowc_lock (void)
  81. {
  82. return &mutex;
  83. }
  84. # elif HAVE_THREADS_H
  85. # include <threads.h>
  86. # include <stdlib.h>
  87. static int volatile init_needed = 1;
  88. static once_flag init_once = ONCE_FLAG_INIT;
  89. static mtx_t mutex;
  90. static void
  91. atomic_init (void)
  92. {
  93. if (mtx_init (&mutex, mtx_plain) != thrd_success)
  94. abort ();
  95. init_needed = 0;
  96. }
  97. /* Make sure the function gets exported from shared libraries. */
  98. DLL_EXPORTED mtx_t *gl_get_mbtowc_lock (void);
  99. /* Returns the internal lock used by mbrtowc and mbrtoc32. */
  100. mtx_t *
  101. gl_get_mbtowc_lock (void)
  102. {
  103. if (init_needed)
  104. call_once (&init_once, atomic_init);
  105. return &mutex;
  106. }
  107. # endif
  108. # if (defined _WIN32 || defined __CYGWIN__) && !defined _MSC_VER
  109. /* Make sure the '__declspec(dllimport)' in mbrtowc.c and mbrtoc32.c does not
  110. cause a link failure when no DLLs are involved. */
  111. # if defined _WIN64 || defined _LP64
  112. # define IMP(x) __imp_##x
  113. # else
  114. # define IMP(x) _imp__##x
  115. # endif
  116. void * IMP(gl_get_mbtowc_lock) = &gl_get_mbtowc_lock;
  117. # endif
  118. #endif