1 /**
2  * WinPR: Windows Portable Runtime
3  * Thread Pool API (Clean-up Group)
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 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <winpr/crt.h>
25 #include <winpr/pool.h>
26 #include <winpr/library.h>
27 
28 #include "pool.h"
29 
30 #ifdef WINPR_THREAD_POOL
31 
32 #ifdef _WIN32
33 static INIT_ONCE init_once_module = INIT_ONCE_STATIC_INIT;
34 static PTP_CLEANUP_GROUP(WINAPI* pCreateThreadpoolCleanupGroup)();
35 static VOID(WINAPI* pCloseThreadpoolCleanupGroupMembers)(PTP_CLEANUP_GROUP ptpcg,
36                                                          BOOL fCancelPendingCallbacks,
37                                                          PVOID pvCleanupContext);
38 static VOID(WINAPI* pCloseThreadpoolCleanupGroup)(PTP_CLEANUP_GROUP ptpcg);
39 
init_module(PINIT_ONCE once,PVOID param,PVOID * context)40 static BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID* context)
41 {
42 	HMODULE kernel32 = LoadLibraryA("kernel32.dll");
43 
44 	if (kernel32)
45 	{
46 		pCreateThreadpoolCleanupGroup =
47 		    (void*)GetProcAddress(kernel32, "CreateThreadpoolCleanupGroup");
48 		pCloseThreadpoolCleanupGroupMembers =
49 		    (void*)GetProcAddress(kernel32, "CloseThreadpoolCleanupGroupMembers");
50 		pCloseThreadpoolCleanupGroup =
51 		    (void*)GetProcAddress(kernel32, "CloseThreadpoolCleanupGroup");
52 	}
53 
54 	return TRUE;
55 }
56 #endif
57 
winpr_CreateThreadpoolCleanupGroup(void)58 PTP_CLEANUP_GROUP winpr_CreateThreadpoolCleanupGroup(void)
59 {
60 	PTP_CLEANUP_GROUP cleanupGroup = NULL;
61 #ifdef _WIN32
62 	InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
63 
64 	if (pCreateThreadpoolCleanupGroup)
65 		return pCreateThreadpoolCleanupGroup();
66 
67 	return cleanupGroup;
68 #else
69 	cleanupGroup = (PTP_CLEANUP_GROUP)calloc(1, sizeof(TP_CLEANUP_GROUP));
70 
71 	if (!cleanupGroup)
72 		return NULL;
73 
74 	cleanupGroup->groups = ArrayList_New(FALSE);
75 
76 	if (!cleanupGroup->groups)
77 	{
78 		free(cleanupGroup);
79 		return NULL;
80 	}
81 
82 	return cleanupGroup;
83 #endif
84 }
85 
winpr_SetThreadpoolCallbackCleanupGroup(PTP_CALLBACK_ENVIRON pcbe,PTP_CLEANUP_GROUP ptpcg,PTP_CLEANUP_GROUP_CANCEL_CALLBACK pfng)86 VOID winpr_SetThreadpoolCallbackCleanupGroup(PTP_CALLBACK_ENVIRON pcbe, PTP_CLEANUP_GROUP ptpcg,
87                                              PTP_CLEANUP_GROUP_CANCEL_CALLBACK pfng)
88 {
89 	pcbe->CleanupGroup = ptpcg;
90 	pcbe->CleanupGroupCancelCallback = pfng;
91 #ifndef _WIN32
92 	pcbe->CleanupGroup->env = pcbe;
93 #endif
94 }
95 
winpr_CloseThreadpoolCleanupGroupMembers(PTP_CLEANUP_GROUP ptpcg,BOOL fCancelPendingCallbacks,PVOID pvCleanupContext)96 VOID winpr_CloseThreadpoolCleanupGroupMembers(PTP_CLEANUP_GROUP ptpcg, BOOL fCancelPendingCallbacks,
97                                               PVOID pvCleanupContext)
98 {
99 #ifdef _WIN32
100 	InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
101 
102 	if (pCloseThreadpoolCleanupGroupMembers)
103 	{
104 		pCloseThreadpoolCleanupGroupMembers(ptpcg, fCancelPendingCallbacks, pvCleanupContext);
105 		return;
106 	}
107 
108 #else
109 
110 	while (ArrayList_Count(ptpcg->groups) > 0)
111 	{
112 		PTP_WORK work = ArrayList_GetItem(ptpcg->groups, 0);
113 		winpr_CloseThreadpoolWork(work);
114 	}
115 
116 #endif
117 }
118 
winpr_CloseThreadpoolCleanupGroup(PTP_CLEANUP_GROUP ptpcg)119 VOID winpr_CloseThreadpoolCleanupGroup(PTP_CLEANUP_GROUP ptpcg)
120 {
121 #ifdef _WIN32
122 	InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
123 
124 	if (pCloseThreadpoolCleanupGroup)
125 	{
126 		pCloseThreadpoolCleanupGroup(ptpcg);
127 		return;
128 	}
129 
130 #else
131 
132 	if (ptpcg && ptpcg->groups)
133 		ArrayList_Free(ptpcg->groups);
134 
135 	if (ptpcg && ptpcg->env)
136 		ptpcg->env->CleanupGroup = NULL;
137 
138 	free(ptpcg);
139 #endif
140 }
141 
142 #endif /* WINPR_THREAD_POOL defined */
143