PageRenderTime 4518ms CodeModel.GetById 51ms RepoModel.GetById 8ms app.codeStats 0ms

/mono/metadata/w32semaphore-unix.c

https://github.com/pruiz/mono
C | 375 lines | 266 code | 83 blank | 26 comment | 28 complexity | dac7b7d7912e3f72f15a363c3385a927 MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. /**
  2. * \file
  3. * Runtime support for managed Semaphore on Unix
  4. *
  5. * Author:
  6. * Ludovic Henry (luhenry@microsoft.com)
  7. *
  8. * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  9. */
  10. #include "w32semaphore.h"
  11. #include "w32error.h"
  12. #include "w32handle-namespace.h"
  13. #include "mono/utils/mono-logger-internals.h"
  14. #include "mono/metadata/w32handle.h"
  15. #define MAX_PATH 260
  16. typedef struct {
  17. guint32 val;
  18. gint32 max;
  19. } MonoW32HandleSemaphore;
  20. struct MonoW32HandleNamedSemaphore {
  21. MonoW32HandleSemaphore s;
  22. MonoW32HandleNamespace sharedns;
  23. };
  24. static void sem_handle_signal (gpointer handle, MonoW32HandleType type, MonoW32HandleSemaphore *sem_handle)
  25. {
  26. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: signalling %s handle %p",
  27. __func__, mono_w32handle_get_typename (type), handle);
  28. /* No idea why max is signed, but thats the spec :-( */
  29. if (sem_handle->val + 1 > (guint32)sem_handle->max) {
  30. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d, max value would be exceeded",
  31. __func__, mono_w32handle_get_typename (type), handle, sem_handle->val, 1, sem_handle->max);
  32. } else {
  33. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d",
  34. __func__, mono_w32handle_get_typename (type), handle, sem_handle->val, 1, sem_handle->max);
  35. sem_handle->val += 1;
  36. mono_w32handle_set_signal_state (handle, TRUE, TRUE);
  37. }
  38. }
  39. static gboolean sem_handle_own (gpointer handle, MonoW32HandleType type, gboolean *abandoned)
  40. {
  41. MonoW32HandleSemaphore *sem_handle;
  42. *abandoned = FALSE;
  43. if (!mono_w32handle_lookup (handle, type, (gpointer *)&sem_handle)) {
  44. g_warning ("%s: error looking up %s handle %p",
  45. __func__, mono_w32handle_get_typename (type), handle);
  46. return FALSE;
  47. }
  48. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p",
  49. __func__, mono_w32handle_get_typename (type), handle);
  50. sem_handle->val--;
  51. if (sem_handle->val == 0)
  52. mono_w32handle_set_signal_state (handle, FALSE, FALSE);
  53. return TRUE;
  54. }
  55. static void sema_signal(gpointer handle, gpointer handle_specific)
  56. {
  57. sem_handle_signal (handle, MONO_W32HANDLE_SEM, (MonoW32HandleSemaphore*) handle_specific);
  58. }
  59. static gboolean sema_own (gpointer handle, gboolean *abandoned)
  60. {
  61. return sem_handle_own (handle, MONO_W32HANDLE_SEM, abandoned);
  62. }
  63. static void namedsema_signal (gpointer handle, gpointer handle_specific)
  64. {
  65. sem_handle_signal (handle, MONO_W32HANDLE_NAMEDSEM, (MonoW32HandleSemaphore*) handle_specific);
  66. }
  67. /* NB, always called with the shared handle lock held */
  68. static gboolean namedsema_own (gpointer handle, gboolean *abandoned)
  69. {
  70. return sem_handle_own (handle, MONO_W32HANDLE_NAMEDSEM, abandoned);
  71. }
  72. static void sema_details (gpointer data)
  73. {
  74. MonoW32HandleSemaphore *sem = (MonoW32HandleSemaphore *)data;
  75. g_print ("val: %5u, max: %5d", sem->val, sem->max);
  76. }
  77. static void namedsema_details (gpointer data)
  78. {
  79. MonoW32HandleNamedSemaphore *namedsem = (MonoW32HandleNamedSemaphore *)data;
  80. g_print ("val: %5u, max: %5d, name: \"%s\"", namedsem->s.val, namedsem->s.max, namedsem->sharedns.name);
  81. }
  82. static const gchar* sema_typename (void)
  83. {
  84. return "Semaphore";
  85. }
  86. static gsize sema_typesize (void)
  87. {
  88. return sizeof (MonoW32HandleSemaphore);
  89. }
  90. static const gchar* namedsema_typename (void)
  91. {
  92. return "N.Semaphore";
  93. }
  94. static gsize namedsema_typesize (void)
  95. {
  96. return sizeof (MonoW32HandleNamedSemaphore);
  97. }
  98. void
  99. mono_w32semaphore_init (void)
  100. {
  101. static MonoW32HandleOps sem_ops = {
  102. NULL, /* close */
  103. sema_signal, /* signal */
  104. sema_own, /* own */
  105. NULL, /* is_owned */
  106. NULL, /* special_wait */
  107. NULL, /* prewait */
  108. sema_details, /* details */
  109. sema_typename, /* typename */
  110. sema_typesize, /* typesize */
  111. };
  112. static MonoW32HandleOps namedsem_ops = {
  113. NULL, /* close */
  114. namedsema_signal, /* signal */
  115. namedsema_own, /* own */
  116. NULL, /* is_owned */
  117. NULL, /* special_wait */
  118. NULL, /* prewait */
  119. namedsema_details, /* details */
  120. namedsema_typename, /* typename */
  121. namedsema_typesize, /* typesize */
  122. };
  123. mono_w32handle_register_ops (MONO_W32HANDLE_SEM, &sem_ops);
  124. mono_w32handle_register_ops (MONO_W32HANDLE_NAMEDSEM, &namedsem_ops);
  125. mono_w32handle_register_capabilities (MONO_W32HANDLE_SEM,
  126. (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL));
  127. mono_w32handle_register_capabilities (MONO_W32HANDLE_NAMEDSEM,
  128. (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL));
  129. }
  130. static gpointer
  131. sem_handle_create (MonoW32HandleSemaphore *sem_handle, MonoW32HandleType type, gint32 initial, gint32 max)
  132. {
  133. gpointer handle;
  134. sem_handle->val = initial;
  135. sem_handle->max = max;
  136. handle = mono_w32handle_new (type, sem_handle);
  137. if (handle == INVALID_HANDLE_VALUE) {
  138. g_warning ("%s: error creating %s handle",
  139. __func__, mono_w32handle_get_typename (type));
  140. mono_w32error_set_last (ERROR_GEN_FAILURE);
  141. return NULL;
  142. }
  143. mono_w32handle_lock_handle (handle);
  144. if (initial != 0)
  145. mono_w32handle_set_signal_state (handle, TRUE, FALSE);
  146. mono_w32handle_unlock_handle (handle);
  147. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p",
  148. __func__, mono_w32handle_get_typename (type), handle);
  149. return handle;
  150. }
  151. static gpointer
  152. sem_create (gint32 initial, gint32 max)
  153. {
  154. MonoW32HandleSemaphore sem_handle;
  155. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle, initial %d max %d",
  156. __func__, mono_w32handle_get_typename (MONO_W32HANDLE_SEM), initial, max);
  157. return sem_handle_create (&sem_handle, MONO_W32HANDLE_SEM, initial, max);
  158. }
  159. static gpointer
  160. namedsem_create (gint32 initial, gint32 max, const gunichar2 *name)
  161. {
  162. gpointer handle;
  163. gchar *utf8_name;
  164. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle, initial %d max %d name \"%s\"",
  165. __func__, mono_w32handle_get_typename (MONO_W32HANDLE_NAMEDSEM), initial, max, (const char*)name);
  166. /* w32 seems to guarantee that opening named objects can't race each other */
  167. mono_w32handle_namespace_lock ();
  168. glong utf8_len = 0;
  169. utf8_name = g_utf16_to_utf8 (name, -1, NULL, &utf8_len, NULL);
  170. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating named sem name [%s] initial %d max %d", __func__, utf8_name, initial, max);
  171. handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDSEM, utf8_name);
  172. if (handle == INVALID_HANDLE_VALUE) {
  173. /* The name has already been used for a different object. */
  174. handle = NULL;
  175. mono_w32error_set_last (ERROR_INVALID_HANDLE);
  176. } else if (handle) {
  177. /* Not an error, but this is how the caller is informed that the semaphore wasn't freshly created */
  178. mono_w32error_set_last (ERROR_ALREADY_EXISTS);
  179. /* mono_w32handle_namespace_search_handle already adds a ref to the handle */
  180. } else {
  181. /* A new named semaphore */
  182. MonoW32HandleNamedSemaphore namedsem_handle;
  183. size_t len = utf8_len < MAX_PATH ? utf8_len : MAX_PATH;
  184. memcpy (&namedsem_handle.sharedns.name [0], utf8_name, len);
  185. namedsem_handle.sharedns.name [len] = '\0';
  186. handle = sem_handle_create ((MonoW32HandleSemaphore*) &namedsem_handle, MONO_W32HANDLE_NAMEDSEM, initial, max);
  187. }
  188. g_free (utf8_name);
  189. mono_w32handle_namespace_unlock ();
  190. return handle;
  191. }
  192. gpointer
  193. ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, gint32 *error)
  194. {
  195. gpointer sem;
  196. if (maximumCount <= 0) {
  197. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: maximumCount <= 0", __func__);
  198. *error = ERROR_INVALID_PARAMETER;
  199. return NULL;
  200. }
  201. if (initialCount > maximumCount || initialCount < 0) {
  202. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: initialCount > maximumCount or < 0", __func__);
  203. *error = ERROR_INVALID_PARAMETER;
  204. return NULL;
  205. }
  206. /* Need to blow away any old errors here, because code tests
  207. * for ERROR_ALREADY_EXISTS on success (!) to see if a
  208. * semaphore was freshly created
  209. */
  210. mono_w32error_set_last (ERROR_SUCCESS);
  211. if (!name)
  212. sem = sem_create (initialCount, maximumCount);
  213. else
  214. sem = namedsem_create (initialCount, maximumCount, mono_string_chars (name));
  215. *error = mono_w32error_get_last ();
  216. return sem;
  217. }
  218. MonoBoolean
  219. ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (gpointer handle, gint32 releaseCount, gint32 *prevcount)
  220. {
  221. MonoW32HandleType type;
  222. MonoW32HandleSemaphore *sem_handle;
  223. MonoBoolean ret;
  224. if (!handle) {
  225. mono_w32error_set_last (ERROR_INVALID_HANDLE);
  226. return FALSE;
  227. }
  228. switch (type = mono_w32handle_get_type (handle)) {
  229. case MONO_W32HANDLE_SEM:
  230. case MONO_W32HANDLE_NAMEDSEM:
  231. break;
  232. default:
  233. mono_w32error_set_last (ERROR_INVALID_HANDLE);
  234. return FALSE;
  235. }
  236. if (!mono_w32handle_lookup (handle, type, (gpointer *)&sem_handle)) {
  237. g_warning ("%s: error looking up sem handle %p", __func__, handle);
  238. return FALSE;
  239. }
  240. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: releasing %s handle %p",
  241. __func__, mono_w32handle_get_typename (type), handle);
  242. mono_w32handle_lock_handle (handle);
  243. /* Do this before checking for count overflow, because overflowing
  244. * max is a listed technique for finding the current value */
  245. if (prevcount)
  246. *prevcount = sem_handle->val;
  247. /* No idea why max is signed, but thats the spec :-( */
  248. if (sem_handle->val + releaseCount > (guint32)sem_handle->max) {
  249. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d, max value would be exceeded",
  250. __func__, mono_w32handle_get_typename (type), handle, sem_handle->val, releaseCount, sem_handle->max);
  251. ret = FALSE;
  252. } else {
  253. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d",
  254. __func__, mono_w32handle_get_typename (type), handle, sem_handle->val, releaseCount, sem_handle->max);
  255. sem_handle->val += releaseCount;
  256. mono_w32handle_set_signal_state (handle, TRUE, TRUE);
  257. ret = TRUE;
  258. }
  259. mono_w32handle_unlock_handle (handle);
  260. return ret;
  261. }
  262. gpointer
  263. ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
  264. {
  265. gpointer handle;
  266. gchar *utf8_name;
  267. *error = ERROR_SUCCESS;
  268. /* w32 seems to guarantee that opening named objects can't race each other */
  269. mono_w32handle_namespace_lock ();
  270. utf8_name = g_utf16_to_utf8 (mono_string_chars (name), -1, NULL, NULL, NULL);
  271. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named sem [%s]", __func__, utf8_name);
  272. handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDSEM, utf8_name);
  273. if (handle == INVALID_HANDLE_VALUE) {
  274. /* The name has already been used for a different object. */
  275. *error = ERROR_INVALID_HANDLE;
  276. goto cleanup;
  277. } else if (!handle) {
  278. /* This name doesn't exist */
  279. *error = ERROR_FILE_NOT_FOUND;
  280. goto cleanup;
  281. }
  282. mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named sem handle %p", __func__, handle);
  283. cleanup:
  284. g_free (utf8_name);
  285. mono_w32handle_namespace_unlock ();
  286. return handle;
  287. }
  288. MonoW32HandleNamespace*
  289. mono_w32semaphore_get_namespace (MonoW32HandleNamedSemaphore *semaphore)
  290. {
  291. return &semaphore->sharedns;
  292. }