/src/rt/critical.c

http://github.com/AlexeyProkhin/druntime · C · 176 lines · 113 code · 29 blank · 34 comment · 13 complexity · 819be97193b302f76c479144bc8efe81 MD5 · raw file

  1. /**
  2. * Implementation of support routines for synchronized blocks.
  3. *
  4. * Copyright: Copyright Digital Mars 2000 - 2010.
  5. * License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
  6. * Authors: Walter Bright, Sean Kelly
  7. */
  8. /* Copyright Digital Mars 2000 - 2010.
  9. * Distributed under the Boost Software License, Version 1.0.
  10. * (See accompanying file LICENSE_1_0.txt or copy at
  11. * http://www.boost.org/LICENSE_1_0.txt)
  12. */
  13. /* ================================= Win32 ============================ */
  14. #if _WIN32
  15. #include <windows.h>
  16. /******************************************
  17. * Enter/exit critical section.
  18. */
  19. /* We don't initialize critical sections unless we actually need them.
  20. * So keep a linked list of the ones we do use, and in the static destructor
  21. * code, walk the list and release them.
  22. */
  23. typedef struct D_CRITICAL_SECTION
  24. {
  25. struct D_CRITICAL_SECTION *next;
  26. CRITICAL_SECTION cs;
  27. } D_CRITICAL_SECTION;
  28. static D_CRITICAL_SECTION *dcs_list;
  29. static D_CRITICAL_SECTION critical_section;
  30. static volatile int inited;
  31. void _d_criticalenter(D_CRITICAL_SECTION *dcs)
  32. {
  33. if (!dcs->next)
  34. {
  35. EnterCriticalSection(&critical_section.cs);
  36. if (!dcs->next) // if, in the meantime, another thread didn't set it
  37. {
  38. dcs->next = dcs_list;
  39. dcs_list = dcs;
  40. InitializeCriticalSection(&dcs->cs);
  41. }
  42. LeaveCriticalSection(&critical_section.cs);
  43. }
  44. EnterCriticalSection(&dcs->cs);
  45. }
  46. void _d_criticalexit(D_CRITICAL_SECTION *dcs)
  47. {
  48. LeaveCriticalSection(&dcs->cs);
  49. }
  50. void _STI_critical_init()
  51. {
  52. if (!inited)
  53. { InitializeCriticalSection(&critical_section.cs);
  54. dcs_list = &critical_section;
  55. inited = 1;
  56. }
  57. }
  58. void _STD_critical_term()
  59. {
  60. if (inited)
  61. { inited = 0;
  62. while (dcs_list)
  63. {
  64. DeleteCriticalSection(&dcs_list->cs);
  65. dcs_list = dcs_list->next;
  66. }
  67. }
  68. }
  69. #endif
  70. /* ================================= linux ============================ */
  71. #if linux || __APPLE__ || __FreeBSD__
  72. #include <stdio.h>
  73. #include <stdlib.h>
  74. #include <pthread.h>
  75. // PTHREAD_MUTEX_RECURSIVE is the "standard" symbol,
  76. // while the _NP version is specific to Linux
  77. #if linux
  78. # ifndef PTHREAD_MUTEX_RECURSIVE
  79. # define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
  80. # endif
  81. #endif
  82. /******************************************
  83. * Enter/exit critical section.
  84. */
  85. /* We don't initialize critical sections unless we actually need them.
  86. * So keep a linked list of the ones we do use, and in the static destructor
  87. * code, walk the list and release them.
  88. */
  89. typedef struct D_CRITICAL_SECTION
  90. {
  91. struct D_CRITICAL_SECTION *next;
  92. pthread_mutex_t cs;
  93. } D_CRITICAL_SECTION;
  94. static D_CRITICAL_SECTION *dcs_list;
  95. static D_CRITICAL_SECTION critical_section;
  96. static pthread_mutexattr_t _criticals_attr;
  97. void _STI_critical_init(void);
  98. void _STD_critical_term(void);
  99. void _d_criticalenter(D_CRITICAL_SECTION *dcs)
  100. {
  101. if (!dcs_list)
  102. { _STI_critical_init();
  103. atexit(_STD_critical_term);
  104. }
  105. //printf("_d_criticalenter(dcs = x%x)\n", dcs);
  106. if (!dcs->next)
  107. {
  108. pthread_mutex_lock(&critical_section.cs);
  109. if (!dcs->next) // if, in the meantime, another thread didn't set it
  110. {
  111. dcs->next = dcs_list;
  112. dcs_list = dcs;
  113. pthread_mutex_init(&dcs->cs, &_criticals_attr);
  114. }
  115. pthread_mutex_unlock(&critical_section.cs);
  116. }
  117. pthread_mutex_lock(&dcs->cs);
  118. }
  119. void _d_criticalexit(D_CRITICAL_SECTION *dcs)
  120. {
  121. //printf("_d_criticalexit(dcs = x%x)\n", dcs);
  122. pthread_mutex_unlock(&dcs->cs);
  123. }
  124. void _STI_critical_init()
  125. {
  126. if (!dcs_list)
  127. { //printf("_STI_critical_init()\n");
  128. pthread_mutexattr_init(&_criticals_attr);
  129. pthread_mutexattr_settype(&_criticals_attr, PTHREAD_MUTEX_RECURSIVE);
  130. // The global critical section doesn't need to be recursive
  131. pthread_mutex_init(&critical_section.cs, 0);
  132. dcs_list = &critical_section;
  133. }
  134. }
  135. void _STD_critical_term()
  136. {
  137. if (dcs_list)
  138. { //printf("_STI_critical_term()\n");
  139. while (dcs_list)
  140. {
  141. //printf("\tlooping... %x\n", dcs_list);
  142. pthread_mutex_destroy(&dcs_list->cs);
  143. dcs_list = dcs_list->next;
  144. }
  145. }
  146. }
  147. #endif