event.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /**
  2. * WinPR: Windows Portable Runtime
  3. * Synchronization Functions
  4. *
  5. * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
  6. * Copyright 2017 Armin Novak <armin.novak@thincast.com>
  7. * Copyright 2017 Thincast Technologies GmbH
  8. *
  9. * Licensed under the Apache License, Version 2.0 (the "License");
  10. * you may not use this file except in compliance with the License.
  11. * You may obtain a copy of the License at
  12. *
  13. * http://www.apache.org/licenses/LICENSE-2.0
  14. *
  15. * Unless required by applicable law or agreed to in writing, software
  16. * distributed under the License is distributed on an "AS IS" BASIS,
  17. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. * See the License for the specific language governing permissions and
  19. * limitations under the License.
  20. */
  21. #ifdef HAVE_CONFIG_H
  22. #include "config.h"
  23. #endif
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <stdlib.h>
  27. #include <winpr/synch.h>
  28. #ifndef _WIN32
  29. #include "synch.h"
  30. #ifdef HAVE_UNISTD_H
  31. #include <unistd.h>
  32. #endif
  33. #ifdef HAVE_SYS_EVENTFD_H
  34. #include <sys/eventfd.h>
  35. #endif
  36. #include <errno.h>
  37. #include "../handle/handle.h"
  38. #include "../pipe/pipe.h"
  39. #include "../log.h"
  40. #define TAG WINPR_TAG("synch.event")
  41. static BOOL EventCloseHandle(HANDLE handle);
  42. static BOOL EventIsHandled(HANDLE handle)
  43. {
  44. WINPR_TIMER* pEvent = (WINPR_TIMER*)handle;
  45. if (!pEvent || (pEvent->Type != HANDLE_TYPE_EVENT))
  46. {
  47. SetLastError(ERROR_INVALID_HANDLE);
  48. return FALSE;
  49. }
  50. return TRUE;
  51. }
  52. static int EventGetFd(HANDLE handle)
  53. {
  54. WINPR_EVENT* event = (WINPR_EVENT*)handle;
  55. if (!EventIsHandled(handle))
  56. return -1;
  57. return event->pipe_fd[0];
  58. }
  59. static BOOL EventCloseHandle_(WINPR_EVENT* event)
  60. {
  61. if (!event)
  62. return FALSE;
  63. if (!event->bAttached)
  64. {
  65. if (event->pipe_fd[0] != -1)
  66. {
  67. close(event->pipe_fd[0]);
  68. event->pipe_fd[0] = -1;
  69. }
  70. if (event->pipe_fd[1] != -1)
  71. {
  72. close(event->pipe_fd[1]);
  73. event->pipe_fd[1] = -1;
  74. }
  75. }
  76. free(event->name);
  77. free(event);
  78. return TRUE;
  79. }
  80. static BOOL EventCloseHandle(HANDLE handle)
  81. {
  82. WINPR_EVENT* event = (WINPR_EVENT*)handle;
  83. if (!EventIsHandled(handle))
  84. return FALSE;
  85. return EventCloseHandle_(event);
  86. }
  87. static HANDLE_OPS ops = { EventIsHandled, EventCloseHandle,
  88. EventGetFd, NULL, /* CleanupHandle */
  89. NULL, NULL,
  90. NULL, NULL,
  91. NULL, NULL,
  92. NULL, NULL,
  93. NULL, NULL,
  94. NULL, NULL,
  95. NULL, NULL,
  96. NULL, NULL };
  97. HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
  98. LPCWSTR lpName)
  99. {
  100. HANDLE handle;
  101. char* name = NULL;
  102. if (lpName)
  103. {
  104. int rc = ConvertFromUnicode(CP_UTF8, 0, lpName, -1, &name, 0, NULL, NULL);
  105. if (rc < 0)
  106. return NULL;
  107. }
  108. handle = CreateEventA(lpEventAttributes, bManualReset, bInitialState, name);
  109. free(name);
  110. return handle;
  111. }
  112. HANDLE CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
  113. LPCSTR lpName)
  114. {
  115. WINPR_EVENT* event = (WINPR_EVENT*)calloc(1, sizeof(WINPR_EVENT));
  116. if (lpEventAttributes)
  117. WLog_WARN(TAG, "%s [%s] does not support lpEventAttributes", __FUNCTION__, lpName);
  118. if (!event)
  119. return NULL;
  120. if (lpName)
  121. event->name = strdup(lpName);
  122. event->bAttached = FALSE;
  123. event->bManualReset = bManualReset;
  124. event->ops = &ops;
  125. WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, FD_READ);
  126. /*
  127. * If this parameter is TRUE, the function creates a manual-reset event object,
  128. * which requires the use of the ResetEvent function to set the event state to nonsignaled.
  129. *
  130. * If this parameter is FALSE, the function creates an auto-reset event object,
  131. * and system automatically resets the event state to nonsignaled after a single waiting thread
  132. * has been released.
  133. */
  134. if (!event->bManualReset)
  135. WLog_ERR(TAG, "auto-reset events not yet implemented");
  136. event->pipe_fd[0] = -1;
  137. event->pipe_fd[1] = -1;
  138. #ifdef HAVE_SYS_EVENTFD_H
  139. /*returns a file descriptor that can be used to refer to the eventfd object*/
  140. event->pipe_fd[0] = eventfd(0, EFD_NONBLOCK);
  141. if (event->pipe_fd[0] < 0)
  142. goto fail;
  143. #else
  144. /*pipe[0] refers to the read end of the pipe.
  145. * pipe[1] refers to the write end of the pipe.
  146. */
  147. if (pipe(event->pipe_fd) < 0)
  148. goto fail;
  149. #endif
  150. if (bInitialState)
  151. {
  152. if (!SetEvent(event))
  153. goto fail;
  154. }
  155. return (HANDLE)event;
  156. fail:
  157. EventCloseHandle_(event);
  158. return NULL;
  159. }
  160. HANDLE CreateEventExW(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCWSTR lpName, DWORD dwFlags,
  161. DWORD dwDesiredAccess)
  162. {
  163. BOOL initial = FALSE;
  164. BOOL manual = FALSE;
  165. if (dwFlags & CREATE_EVENT_INITIAL_SET)
  166. initial = TRUE;
  167. if (dwFlags & CREATE_EVENT_MANUAL_RESET)
  168. manual = TRUE;
  169. if (dwDesiredAccess != 0)
  170. WLog_WARN(TAG, "%s [%s] does not support dwDesiredAccess 0x%08" PRIx32, __FUNCTION__,
  171. lpName, dwDesiredAccess);
  172. return CreateEventW(lpEventAttributes, manual, initial, lpName);
  173. }
  174. HANDLE CreateEventExA(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCSTR lpName, DWORD dwFlags,
  175. DWORD dwDesiredAccess)
  176. {
  177. BOOL initial = FALSE;
  178. BOOL manual = FALSE;
  179. if (dwFlags & CREATE_EVENT_INITIAL_SET)
  180. initial = TRUE;
  181. if (dwFlags & CREATE_EVENT_MANUAL_RESET)
  182. manual = TRUE;
  183. if (dwDesiredAccess != 0)
  184. WLog_WARN(TAG, "%s [%s] does not support dwDesiredAccess 0x%08" PRIx32, __FUNCTION__,
  185. lpName, dwDesiredAccess);
  186. return CreateEventA(lpEventAttributes, manual, initial, lpName);
  187. }
  188. HANDLE OpenEventW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
  189. {
  190. /* TODO: Implement */
  191. WINPR_UNUSED(dwDesiredAccess);
  192. WINPR_UNUSED(bInheritHandle);
  193. WINPR_UNUSED(lpName);
  194. WLog_ERR(TAG, "%s not implemented", __FUNCTION__);
  195. return NULL;
  196. }
  197. HANDLE OpenEventA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName)
  198. {
  199. /* TODO: Implement */
  200. WINPR_UNUSED(dwDesiredAccess);
  201. WINPR_UNUSED(bInheritHandle);
  202. WINPR_UNUSED(lpName);
  203. WLog_ERR(TAG, "%s not implemented", __FUNCTION__);
  204. return NULL;
  205. }
  206. #ifdef HAVE_SYS_EVENTFD_H
  207. #if !defined(WITH_EVENTFD_READ_WRITE)
  208. static int eventfd_read(int fd, eventfd_t* value)
  209. {
  210. return (read(fd, value, sizeof(*value)) == sizeof(*value)) ? 0 : -1;
  211. }
  212. static int eventfd_write(int fd, eventfd_t value)
  213. {
  214. return (write(fd, &value, sizeof(value)) == sizeof(value)) ? 0 : -1;
  215. }
  216. #endif
  217. #endif
  218. BOOL SetEvent(HANDLE hEvent)
  219. {
  220. ULONG Type;
  221. WINPR_HANDLE* Object;
  222. int length;
  223. BOOL status;
  224. WINPR_EVENT* event;
  225. status = FALSE;
  226. if (winpr_Handle_GetInfo(hEvent, &Type, &Object))
  227. {
  228. event = (WINPR_EVENT*)Object;
  229. #ifdef HAVE_SYS_EVENTFD_H
  230. eventfd_t val = 1;
  231. do
  232. {
  233. length = eventfd_write(event->pipe_fd[0], val);
  234. } while ((length < 0) && (errno == EINTR)); /*EINTR: the call was interrupted by a signal before the data was written*/
  235. status = (length == 0) ? TRUE : FALSE;
  236. #else
  237. if (WaitForSingleObject(hEvent, 0) != WAIT_OBJECT_0)
  238. {
  239. length = write(event->pipe_fd[1], "-", 1);
  240. if (length == 1)
  241. status = TRUE;
  242. }
  243. else
  244. {
  245. status = TRUE;
  246. }
  247. #endif
  248. }
  249. return status;
  250. }
  251. BOOL ResetEvent(HANDLE hEvent)
  252. {
  253. ULONG Type;
  254. WINPR_HANDLE* Object;
  255. int length;
  256. BOOL status = TRUE;
  257. WINPR_EVENT* event;
  258. if (!winpr_Handle_GetInfo(hEvent, &Type, &Object))
  259. return FALSE;
  260. event = (WINPR_EVENT*)Object;
  261. while (status && WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0)
  262. {
  263. do
  264. {
  265. #ifdef HAVE_SYS_EVENTFD_H
  266. eventfd_t value;
  267. length = eventfd_read(event->pipe_fd[0], &value);
  268. #else
  269. length = read(event->pipe_fd[0], &length, 1);
  270. #endif
  271. } while ((length < 0) && (errno == EINTR));
  272. if (length < 0)
  273. status = FALSE;
  274. }
  275. return status;
  276. }
  277. #endif
  278. HANDLE CreateFileDescriptorEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
  279. BOOL bInitialState, int FileDescriptor, ULONG mode)
  280. {
  281. #ifndef _WIN32
  282. WINPR_EVENT* event;
  283. HANDLE handle = NULL;
  284. event = (WINPR_EVENT*)calloc(1, sizeof(WINPR_EVENT));
  285. if (event)
  286. {
  287. event->bAttached = TRUE;
  288. event->bManualReset = bManualReset;
  289. event->pipe_fd[0] = FileDescriptor;
  290. event->pipe_fd[1] = -1;
  291. event->ops = &ops;
  292. WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, mode);
  293. handle = (HANDLE)event;
  294. }
  295. return handle;
  296. #else
  297. return NULL;
  298. #endif
  299. }
  300. HANDLE CreateFileDescriptorEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
  301. BOOL bInitialState, int FileDescriptor, ULONG mode)
  302. {
  303. return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
  304. FileDescriptor, mode);
  305. }
  306. /**
  307. * Returns an event based on the handle returned by GetEventWaitObject()
  308. */
  309. HANDLE CreateWaitObjectEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
  310. BOOL bInitialState, void* pObject)
  311. {
  312. #ifndef _WIN32
  313. return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
  314. (int)(ULONG_PTR)pObject, WINPR_FD_READ);
  315. #else
  316. HANDLE hEvent = NULL;
  317. DuplicateHandle(GetCurrentProcess(), pObject, GetCurrentProcess(), &hEvent, 0, FALSE,
  318. DUPLICATE_SAME_ACCESS);
  319. return hEvent;
  320. #endif
  321. }
  322. /*
  323. * Returns inner file descriptor for usage with select()
  324. * This file descriptor is not usable on Windows
  325. */
  326. int GetEventFileDescriptor(HANDLE hEvent)
  327. {
  328. #ifndef _WIN32
  329. return winpr_Handle_getFd(hEvent);
  330. #else
  331. return -1;
  332. #endif
  333. }
  334. /*
  335. * Set inner file descriptor for usage with select()
  336. * This file descriptor is not usable on Windows
  337. */
  338. int SetEventFileDescriptor(HANDLE hEvent, int FileDescriptor, ULONG mode)
  339. {
  340. #ifndef _WIN32
  341. ULONG Type;
  342. WINPR_HANDLE* Object;
  343. WINPR_EVENT* event;
  344. if (!winpr_Handle_GetInfo(hEvent, &Type, &Object))
  345. return -1;
  346. event = (WINPR_EVENT*)Object;
  347. if (!event->bAttached && event->pipe_fd[0] >= 0 && event->pipe_fd[0] != FileDescriptor)
  348. close(event->pipe_fd[0]);
  349. event->bAttached = TRUE;
  350. event->Mode = mode;
  351. event->pipe_fd[0] = FileDescriptor;
  352. return 0;
  353. #else
  354. return -1;
  355. #endif
  356. }
  357. /**
  358. * Returns platform-specific wait object as a void pointer
  359. *
  360. * On Windows, the returned object is the same as the hEvent
  361. * argument and is an event HANDLE usable in WaitForMultipleObjects
  362. *
  363. * On other platforms, the returned object can be cast to an int
  364. * to obtain a file descriptor usable in select()
  365. */
  366. void* GetEventWaitObject(HANDLE hEvent)
  367. {
  368. #ifndef _WIN32
  369. int fd;
  370. void* obj;
  371. fd = GetEventFileDescriptor(hEvent);
  372. obj = ((void*)(long)fd);
  373. return obj;
  374. #else
  375. return hEvent;
  376. #endif
  377. }