work.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /**
  2. * WinPR: Windows Portable Runtime
  3. * Thread Pool API (Work)
  4. *
  5. * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. #include "config.h"
  21. #endif
  22. #include <winpr/crt.h>
  23. #include <winpr/pool.h>
  24. #include <winpr/library.h>
  25. #include "pool.h"
  26. #include "../log.h"
  27. #define TAG WINPR_TAG("pool")
  28. #ifdef WINPR_THREAD_POOL
  29. #ifdef _WIN32
  30. static INIT_ONCE init_once_module = INIT_ONCE_STATIC_INIT;
  31. static PTP_WORK(WINAPI* pCreateThreadpoolWork)(PTP_WORK_CALLBACK pfnwk, PVOID pv,
  32. PTP_CALLBACK_ENVIRON pcbe);
  33. static VOID(WINAPI* pCloseThreadpoolWork)(PTP_WORK pwk);
  34. static VOID(WINAPI* pSubmitThreadpoolWork)(PTP_WORK pwk);
  35. static BOOL(WINAPI* pTrySubmitThreadpoolCallback)(PTP_SIMPLE_CALLBACK pfns, PVOID pv,
  36. PTP_CALLBACK_ENVIRON pcbe);
  37. static VOID(WINAPI* pWaitForThreadpoolWorkCallbacks)(PTP_WORK pwk, BOOL fCancelPendingCallbacks);
  38. static BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID* context)
  39. {
  40. HMODULE kernel32 = LoadLibraryA("kernel32.dll");
  41. if (kernel32)
  42. {
  43. pCreateThreadpoolWork = (void*)GetProcAddress(kernel32, "CreateThreadpoolWork");
  44. pCloseThreadpoolWork = (void*)GetProcAddress(kernel32, "CloseThreadpoolWork");
  45. pSubmitThreadpoolWork = (void*)GetProcAddress(kernel32, "SubmitThreadpoolWork");
  46. pTrySubmitThreadpoolCallback =
  47. (void*)GetProcAddress(kernel32, "TrySubmitThreadpoolCallback");
  48. pWaitForThreadpoolWorkCallbacks =
  49. (void*)GetProcAddress(kernel32, "WaitForThreadpoolWorkCallbacks");
  50. }
  51. return TRUE;
  52. }
  53. #endif
  54. static TP_CALLBACK_ENVIRON DEFAULT_CALLBACK_ENVIRONMENT = {
  55. 1, /* Version */
  56. NULL, /* Pool */
  57. NULL, /* CleanupGroup */
  58. NULL, /* CleanupGroupCancelCallback */
  59. NULL, /* RaceDll */
  60. NULL, /* ActivationContext */
  61. NULL, /* FinalizationCallback */
  62. { 0 } /* Flags */
  63. };
  64. PTP_WORK winpr_CreateThreadpoolWork(PTP_WORK_CALLBACK pfnwk, PVOID pv, PTP_CALLBACK_ENVIRON pcbe)
  65. {
  66. PTP_WORK work = NULL;
  67. #ifdef _WIN32
  68. InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
  69. if (pCreateThreadpoolWork)
  70. return pCreateThreadpoolWork(pfnwk, pv, pcbe);
  71. #endif
  72. work = (PTP_WORK)calloc(1, sizeof(TP_WORK));
  73. if (work)
  74. {
  75. if (!pcbe)
  76. {
  77. pcbe = &DEFAULT_CALLBACK_ENVIRONMENT;
  78. pcbe->Pool = GetDefaultThreadpool();
  79. }
  80. work->CallbackEnvironment = pcbe;
  81. work->WorkCallback = pfnwk;
  82. work->CallbackParameter = pv;
  83. #ifndef _WIN32
  84. if (pcbe->CleanupGroup)
  85. ArrayList_Add(pcbe->CleanupGroup->groups, work);
  86. #endif
  87. }
  88. return work;
  89. }
  90. VOID winpr_CloseThreadpoolWork(PTP_WORK pwk)
  91. {
  92. #ifdef _WIN32
  93. InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
  94. if (pCloseThreadpoolWork)
  95. {
  96. pCloseThreadpoolWork(pwk);
  97. return;
  98. }
  99. #else
  100. if (pwk->CallbackEnvironment->CleanupGroup)
  101. ArrayList_Remove(pwk->CallbackEnvironment->CleanupGroup->groups, pwk);
  102. #endif
  103. free(pwk);
  104. }
  105. VOID winpr_SubmitThreadpoolWork(PTP_WORK pwk)
  106. {
  107. PTP_POOL pool;
  108. PTP_CALLBACK_INSTANCE callbackInstance;
  109. #ifdef _WIN32
  110. InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
  111. if (pSubmitThreadpoolWork)
  112. {
  113. pSubmitThreadpoolWork(pwk);
  114. return;
  115. }
  116. #endif
  117. pool = pwk->CallbackEnvironment->Pool;
  118. callbackInstance = (PTP_CALLBACK_INSTANCE)calloc(1, sizeof(TP_CALLBACK_INSTANCE));
  119. if (callbackInstance)
  120. {
  121. callbackInstance->Work = pwk;
  122. CountdownEvent_AddCount(pool->WorkComplete, 1);
  123. Queue_Enqueue(pool->PendingQueue, callbackInstance);
  124. }
  125. }
  126. BOOL winpr_TrySubmitThreadpoolCallback(PTP_SIMPLE_CALLBACK pfns, PVOID pv,
  127. PTP_CALLBACK_ENVIRON pcbe)
  128. {
  129. #ifdef _WIN32
  130. InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
  131. if (pTrySubmitThreadpoolCallback)
  132. return pTrySubmitThreadpoolCallback(pfns, pv, pcbe);
  133. #endif
  134. WLog_ERR(TAG, "TrySubmitThreadpoolCallback is not implemented");
  135. return FALSE;
  136. }
  137. VOID winpr_WaitForThreadpoolWorkCallbacks(PTP_WORK pwk, BOOL fCancelPendingCallbacks)
  138. {
  139. HANDLE event;
  140. PTP_POOL pool;
  141. #ifdef _WIN32
  142. InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
  143. if (pWaitForThreadpoolWorkCallbacks)
  144. {
  145. pWaitForThreadpoolWorkCallbacks(pwk, fCancelPendingCallbacks);
  146. return;
  147. }
  148. #endif
  149. pool = pwk->CallbackEnvironment->Pool;
  150. event = CountdownEvent_WaitHandle(pool->WorkComplete);
  151. if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0)
  152. WLog_ERR(TAG, "error waiting on work completion");
  153. }
  154. #endif /* WINPR_THREAD_POOL defined */