Windows: fix checked UNICODE build of talocale
[openafs.git] / src / WINNT / afsapplib / al_task.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <winsock2.h>
11 #include <ws2tcpip.h>
12
13 extern "C" {
14 #include <afs/param.h>
15 #include <afs/stds.h>
16 }
17
18 #include <WINNT/afsapplib.h>
19
20
21 /*
22  * VARIABLES __________________________________________________________________
23  *
24  */
25
26 static LPTASKQUEUE_PARAMS ptqp = NULL;
27
28 typedef struct TASKQUEUEITEM
29    {
30    struct TASKQUEUEITEM *pNext;
31    int idTask;
32    HWND hReply;
33    PVOID lpUser;
34    } TASKQUEUEITEM, *LPTASKQUEUEITEM;
35
36 static LPTASKQUEUEITEM pTaskQueuePop = NULL;
37 static LPTASKQUEUEITEM pTaskQueuePushAfter = NULL;
38 static CRITICAL_SECTION csTaskQueue;
39
40 static size_t nThreadsRunning = 0;
41 static size_t nRequestsActive = 0;
42
43
44
45 /*
46  * PROTOTYPES _________________________________________________________________
47  *
48  */
49
50 DWORD WINAPI Task_ThreadProc (PVOID lp);
51
52
53 /*
54  * ROUTINES ___________________________________________________________________
55  *
56  */
57
58 void AfsAppLib_InitTaskQueue (LPTASKQUEUE_PARAMS lpp)
59 {
60    if (ptqp != NULL)
61       {
62       Delete (ptqp);
63       ptqp = NULL;
64       }
65
66    if (lpp && lpp->fnCreateTaskPacket && lpp->fnPerformTask && lpp->fnFreeTaskPacket)
67       {
68       ptqp = New (TASKQUEUE_PARAMS);
69       memcpy (ptqp, lpp, sizeof(TASKQUEUE_PARAMS));
70       }
71 }
72
73
74 void StartTask (int idTask, HWND hReply, PVOID lpUser)
75 {
76    if (!ptqp)
77       return;
78
79    static BOOL fStarted = FALSE;
80    if (!fStarted)
81       {
82       fStarted = TRUE;
83       InitializeCriticalSection (&csTaskQueue);
84       }
85
86    // Then push this notification onto our TaskQueue, so that the task
87    // thread will pop off each request in turn and take a look at it.
88    // Ideally, PostThreadMessage() and GetMessage() would implement all this
89    // garbage, but that doesn't work properly for some reason...
90    //
91    EnterCriticalSection (&csTaskQueue);
92
93    if ((++nRequestsActive) > nThreadsRunning)
94       {
95       if ((!ptqp->nThreadsMax) || (nThreadsRunning < (size_t)(ptqp->nThreadsMax)))
96          {
97          DWORD dwThreadID;
98          HANDLE hThread;
99          if ((hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)Task_ThreadProc, 0, 0, &dwThreadID)) != NULL)
100             {
101             SetThreadPriority (hThread, THREAD_PRIORITY_BELOW_NORMAL);
102             ++nThreadsRunning;
103             }
104          }
105       }
106
107    LPTASKQUEUEITEM lptqi = New (TASKQUEUEITEM);
108    lptqi->pNext = NULL;
109    lptqi->idTask = idTask;
110    lptqi->hReply = hReply;
111    lptqi->lpUser = lpUser;
112
113    if (pTaskQueuePushAfter != NULL)
114       pTaskQueuePushAfter->pNext = lptqi;
115    pTaskQueuePushAfter = lptqi;
116
117    if (pTaskQueuePop == NULL)
118       pTaskQueuePop = lptqi;
119
120    LeaveCriticalSection (&csTaskQueue);
121 }
122
123
124 DWORD WINAPI Task_ThreadProc (PVOID lp)
125 {
126    BOOL fJustDidTask = FALSE;
127
128    for (;;)
129       {
130       BOOL fFound = FALSE;
131       TASKQUEUEITEM tqi;
132
133       EnterCriticalSection (&csTaskQueue);
134
135       if (fJustDidTask)
136          {
137          --nRequestsActive;
138          fJustDidTask = FALSE;
139          }
140
141       if (pTaskQueuePop != NULL)
142          {
143          LPTASKQUEUEITEM lptqiNext = pTaskQueuePop->pNext;
144          tqi = *pTaskQueuePop;
145          Delete (pTaskQueuePop);
146          if (pTaskQueuePushAfter == pTaskQueuePop)
147             pTaskQueuePushAfter = NULL;
148          pTaskQueuePop = lptqiNext;
149          fFound = TRUE;
150          fJustDidTask = TRUE;
151          }
152
153       // is this thread unnecessary?--that is, if we couldn't find anything
154       // to do, then kill off all threads.
155       //
156       if (!fFound)
157          {
158          --nThreadsRunning;
159          LeaveCriticalSection (&csTaskQueue);
160          break;
161          }
162
163       LeaveCriticalSection (&csTaskQueue);
164
165       if (fFound)
166          {
167          LPTASKPACKET ptp;
168          if ((ptp = (*ptqp->fnCreateTaskPacket)(tqi.idTask, tqi.hReply, tqi.lpUser)) != NULL)
169             {
170             (*ptqp->fnPerformTask)(ptp);
171             }
172
173          if (tqi.hReply && IsWindow (tqi.hReply))
174             {
175             PostMessage (tqi.hReply, WM_ENDTASK, 0, (LPARAM)ptp);
176             }
177          else if (ptp != NULL)
178             {
179             (*ptqp->fnFreeTaskPacket)(ptp);
180             }
181          }
182       }
183
184    return 0;
185 }
186