source: trunk/src/user32/auxthread.cpp@ 21599

Last change on this file since 21599 was 21599, checked in by dmik, 14 years ago

user32: auxthread: Typo.

  • Property svn:eol-style set to native
File size: 7.9 KB
Line 
1/*
2 * Auxiliary thread API
3 *
4 * Used to execute code on a dedicated thread.
5 *
6 * Project Odin Software License can be found in LICENSE.TXT
7 *
8 */
9
10#define INCL_PM
11#define INCL_DOS
12#define INCL_DOSERRORS
13#include <os2wrap.h> // Odin32 OS/2 api wrappers
14
15#include <win32api.h>
16
17#include "auxthread.h"
18
19#include "dbglog.h"
20
21struct AUXMSG
22{
23 PAUXTHREADFN pfn;
24 PVOID arg1;
25 PVOID arg2;
26 PVOID arg3;
27 PVOID arg4;
28 BOOL del;
29};
30
31static HEV hevAux = 0;
32static HANDLE hthreadAux = 0;
33static HWND hwndAux = NULLHANDLE;
34
35static MRESULT EXPENTRY AuxWndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
36{
37 if (msg == WM_USER)
38 {
39 AUXMSG *msg = (AUXMSG *)mp1;
40 MRESULT mrc = msg->pfn(msg->arg1, msg->arg2, msg->arg3, msg->arg4);
41 if (msg->del)
42 delete msg;
43 return mrc;
44 }
45
46 return FALSE;
47}
48
49static DWORD CALLBACK AuxThread(LPVOID arg)
50{
51 // take hev from the parameter instead of hevAux which will have gone right
52 // after calling StopAuxThread() so that we won't be able to post it
53 HEV hev = (HEV)arg;
54
55 dprintf(("USER32: AuxThread: Start (hev %x)", hev));
56
57 // Note: Since this thread is started by CreateThread(), hab and hmq are
58 // already created
59
60 if (WinRegisterClass(0, "OdinAuxWnd", AuxWndProc, 0, 0))
61 {
62 hwndAux = WinCreateWindow(HWND_OBJECT, "OdinAuxWnd", NULL,
63 0, 0, 0, 0, 0, NULL, HWND_BOTTOM, 0,
64 NULL, NULL);
65 if (hwndAux)
66 {
67 // report becoming ready (non-NULL hwndAux will indicate success)
68 DosPostEventSem(hev);
69
70 dprintf(("USER32: AuxThread: Enter message loop"));
71
72 QMSG qmsg;
73 while (WinGetMsg(0, &qmsg, NULLHANDLE, 0, 0))
74 WinDispatchMsg(0, &qmsg);
75
76 dprintf(("USER32: AuxThread: Exit message loop"));
77
78 WinDestroyWindow(hwndAux);
79 }
80 else
81 dprintf(("USER32: AuxThread: WinCreateWindow() failed with %x",
82 WinGetLastError(0)));
83
84 }
85 else
86 dprintf(("USER32: AuxThread: WinRegisterClass() failed with %x",
87 WinGetLastError(0)));
88
89 dprintf(("USER32: AuxThread: Stop"));
90
91 // report termination
92 DosPostEventSem(hev);
93
94 return 0;
95}
96
97static BOOL DoRunOnAuxThread(PAUXTHREADFN pfn, PVOID arg1, PVOID arg2,
98 PVOID arg3, PVOID arg4, PVOID *ret)
99{
100 APIRET arc;
101
102 if (hevAux == 0)
103 {
104 HEV hev;
105 arc = DosCreateEventSem(NULL, &hev, 0, FALSE);
106 if (arc != NO_ERROR)
107 {
108 dprintf(("USER32: AuxThread: DosCreateEventSem failed with %d",
109 arc));
110 return FALSE;
111 }
112
113 // protect from two or more concurrent "first" calls
114 if (InterlockedCompareExchange((PLONG)&hevAux, hev, 0) == 0)
115 {
116 // we are the first, do the rest
117
118 // Note: Use CreateThread() instead of DosCreateThread() so that the
119 // thread gets all initialization necessary to call Win32 APIs which
120 // may be potentially called form PAUXTHREADFN
121 hthreadAux = CreateThread(NULL, 0, AuxThread, (LPVOID)hev, 0, NULL);
122 if (hthreadAux)
123 {
124 // wait for the thread to get ready
125 arc = DosWaitEventSem(hev, SEM_INDEFINITE_WAIT);
126 }
127 else
128 {
129 dprintf(("USER32: AuxThread: CreateThread() failed with %x",
130 GetLastError()));
131
132 // the second caller may be already waiting so inform it
133 DosPostEventSem(hev);
134 }
135 }
136 else
137 {
138 // we are the second, give up our attempt
139 DosCloseEventSem(hev);
140
141 // wait for the thread to get ready
142 arc = DosWaitEventSem(hevAux, SEM_INDEFINITE_WAIT);
143 }
144
145 if (hthreadAux == 0 || arc != NO_ERROR || hwndAux == NULLHANDLE)
146 {
147 StopAuxThread(); // cleanup
148 return FALSE;
149 }
150 }
151
152 if (ret)
153 {
154 AUXMSG msg = { pfn, arg1, arg2, arg3, arg4, FALSE };
155 *ret = WinSendMsg(hwndAux, WM_USER, &msg, 0);
156 return TRUE;
157 }
158
159 AUXMSG *msg = new AUXMSG;
160 msg->pfn = pfn;
161 msg->arg1 = arg1;
162 msg->arg2 = arg2;
163 msg->arg3 = arg3;
164 msg->arg4 = arg4;
165 msg->del = TRUE;
166 if (WinPostMsg(hwndAux, WM_USER, msg, 0))
167 return TRUE;
168
169 delete msg;
170 return FALSE;
171}
172
173/**
174 * Schedules execution of a given user function with given arguments on a
175 * dedicated global helper thread and immediately returns to the caller.
176 *
177 * All calls to RunOnAuxThread() schedule execution of the user function on the
178 * same thread which, once started, gets terminated automatically at process
179 * termination.
180 *
181 * Note that since this thread is global (shared by all requests as described
182 * above), the user function must return as soon as possible as other threads
183 * may be trying to schedule a function call on this thread through
184 * RunOnAuxThread() (or even waiting for the result of the function execution
185 * through RunOnAuxThreadAndWait()) as well.
186 *
187 * The main purpose of this API is to make sure that a series of function calls
188 * is guaranteedly performed on the same thread so that subsequent calls share
189 * the context established by the fisrt call. This, in particular includes
190 * situations when it is necessary to make sure that an object window is
191 * destroyed on the same thead where it was created no matter what thread calls
192 * the create or destroy code. This also implies that this dedicated thread runs
193 * the message loop and therefore may respond to posted messages.
194 *
195 * @author dmik (3/23/2011)
196 *
197 * @param pfn User function to execute.
198 * @param arg1 Function argument 1.
199 * @param arg2 Function argument 2.
200 * @param arg3 Function argument 3.
201 * @param arg4 Function argument 4.
202 *
203 * @return TRUE on success, FALSE otherwise.
204 */
205BOOL WIN32API RunOnAuxThread(PAUXTHREADFN pfn, PVOID arg1, PVOID arg2,
206 PVOID arg3, PVOID arg4)
207{
208 return DoRunOnAuxThread(pfn, arg1, arg2, arg3, arg4, NULL);
209}
210
211/**
212 * Schedules execution of a given user function with given arguments on a
213 * dedicated global helper thread and waits for it to return a value.
214 *
215 * See RunOnAuxThread() for more details on the dedicated thread and purpose of
216 * this API.
217 *
218 * @author dmik (3/23/2011)
219 *
220 * @param pfn User function to execute.
221 * @param arg1 Function argument 1.
222 * @param arg2 Function argument 2.
223 * @param arg3 Function argument 3.
224 * @param arg4 Function argument 4.
225 * @param ret Where to store the user function's return value. May be NULL if
226 * the caller is not interested in the return value.
227 *
228 * @return TRUE on success, FALSE otherwise.
229 */
230BOOL WIN32API RunOnAuxThreadAndWait(PAUXTHREADFN pfn, PVOID arg1, PVOID arg2,
231 PVOID arg3, PVOID arg4, PPVOID ret)
232{
233 PVOID ret2;
234 BOOL brc = DoRunOnAuxThread(pfn, arg1, arg2, arg3, arg4, &ret2);
235 if (ret)
236 *ret = ret2;
237 return brc;
238}
239
240//******************************************************************************
241//
242//******************************************************************************
243VOID StopAuxThread()
244{
245 if (hevAux != 0)
246 {
247 HEV hev = hevAux;
248
249 // protect from two or more concurrent "first" calls
250 if (InterlockedCompareExchange((PLONG)&hevAux, 0, hev) == hev)
251 {
252 // we are the first, do the rest
253
254 // ask to exit the message loop
255 if (hwndAux)
256 {
257 ULONG dummy;
258 DosResetEventSem(hev, &dummy);
259
260 WinPostMsg(hwndAux, WM_QUIT, 0, 0);
261 hwndAux = NULLHANDLE;
262 }
263
264 if (hthreadAux != 0)
265 {
266 // wait for the normal thread termination
267 DosWaitEventSem(hev, 3000);
268 CloseHandle(hthreadAux);
269 hthreadAux = 0;
270 }
271
272 DosCloseEventSem(hev);
273 }
274 }
275}
Note: See TracBrowser for help on using the repository browser.