4 * Copyright (c) 2006 Robert Shearman
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
27 #define NONAMELESSUNION
29 #define WIN32_NO_STATUS
32 #include "wine/debug.h"
33 #include "wine/list.h"
35 #include "ntdll_misc.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(threadpool
);
39 #define WORKER_TIMEOUT 30000 /* 30 seconds */
41 static LONG num_workers
;
42 static LONG num_work_items
;
43 static LONG num_busy_workers
;
45 static struct list work_item_list
= LIST_INIT(work_item_list
);
46 static HANDLE work_item_event
;
48 static RTL_CRITICAL_SECTION threadpool_cs
;
49 static RTL_CRITICAL_SECTION_DEBUG critsect_debug
=
52 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
53 0, 0, { (DWORD_PTR
)(__FILE__
": threadpool_cs") }
55 static RTL_CRITICAL_SECTION threadpool_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
60 PRTL_WORK_ITEM_ROUTINE function
;
64 static inline LONG
interlocked_inc( PLONG dest
)
66 return interlocked_xchg_add( (int *)dest
, 1 ) + 1;
69 static inline LONG
interlocked_dec( PLONG dest
)
71 return interlocked_xchg_add( (int *)dest
, -1 ) - 1;
74 static void WINAPI
worker_thread_proc(void * param
)
76 interlocked_inc(&num_workers
);
78 /* free the work item memory sooner to reduce memory usage */
81 if (num_work_items
> 0)
84 RtlEnterCriticalSection(&threadpool_cs
);
85 item
= list_head(&work_item_list
);
88 struct work_item
*work_item_ptr
= LIST_ENTRY(item
, struct work_item
, entry
);
89 struct work_item work_item
;
90 list_remove(&work_item_ptr
->entry
);
91 interlocked_dec(&num_work_items
);
93 RtlLeaveCriticalSection(&threadpool_cs
);
95 work_item
= *work_item_ptr
;
96 RtlFreeHeap(GetProcessHeap(), 0, work_item_ptr
);
98 TRACE("executing %p(%p)\n", work_item
.function
, work_item
.context
);
100 interlocked_inc(&num_busy_workers
);
103 work_item
.function(work_item
.context
);
105 interlocked_dec(&num_busy_workers
);
108 RtlLeaveCriticalSection(&threadpool_cs
);
113 LARGE_INTEGER timeout
;
114 timeout
.QuadPart
= -(WORKER_TIMEOUT
* (ULONGLONG
)10000);
115 status
= NtWaitForSingleObject(work_item_event
, FALSE
, &timeout
);
116 if (status
!= STATUS_WAIT_0
)
121 interlocked_dec(&num_workers
);
123 RtlExitUserThread(0);
128 static NTSTATUS
add_work_item_to_queue(struct work_item
*work_item
)
132 RtlEnterCriticalSection(&threadpool_cs
);
133 list_add_tail(&work_item_list
, &work_item
->entry
);
135 RtlLeaveCriticalSection(&threadpool_cs
);
137 if (!work_item_event
)
140 status
= NtCreateSemaphore(&sem
, SEMAPHORE_ALL_ACCESS
, NULL
, 1, LONG_MAX
);
141 if (interlocked_cmpxchg_ptr( (PVOID
*)&work_item_event
, (PVOID
)sem
, 0 ))
142 NtClose(sem
); /* somebody beat us to it */
145 status
= NtReleaseSemaphore(work_item_event
, 1, NULL
);
150 /***********************************************************************
151 * RtlQueueWorkItem (NTDLL.@)
153 * Queues a work item into a thread in the thread pool.
156 * Function [I] Work function to execute.
157 * Context [I] Context to pass to the work function when it is executed.
158 * Flags [I] Flags. See notes.
161 * Success: STATUS_SUCCESS.
162 * Failure: Any NTSTATUS code.
165 * Flags can be one or more of the following:
166 *|WT_EXECUTEDEFAULT - Executes the work item in a non-I/O worker thread.
167 *|WT_EXECUTEINIOTHREAD - Executes the work item in an I/O worker thread.
168 *|WT_EXECUTEINPERSISTENTTHREAD - Executes the work item in a thread that is persistent.
169 *|WT_EXECUTELONGFUNCTION - Hints that the execution can take a long time.
170 *|WT_TRANSFER_IMPERSONATION - Executes the function with the current access token.
172 NTSTATUS WINAPI
RtlQueueWorkItem(PRTL_WORK_ITEM_ROUTINE Function
, PVOID Context
, ULONG Flags
)
176 struct work_item
*work_item
= RtlAllocateHeap(GetProcessHeap(), 0, sizeof(struct work_item
));
179 return STATUS_NO_MEMORY
;
181 work_item
->function
= Function
;
182 work_item
->context
= Context
;
184 if (Flags
& ~WT_EXECUTELONGFUNCTION
)
185 FIXME("Flags 0x%x not supported\n", Flags
);
187 status
= add_work_item_to_queue(work_item
);
189 /* FIXME: tune this algorithm to not be as aggressive with creating threads
190 * if WT_EXECUTELONGFUNCTION isn't specified */
191 if ((status
== STATUS_SUCCESS
) &&
192 ((num_workers
== 0) || (num_workers
== num_busy_workers
)))
194 status
= RtlCreateUserThread( GetCurrentProcess(), NULL
, FALSE
,
196 worker_thread_proc
, NULL
, &thread
, NULL
);
197 if (status
== STATUS_SUCCESS
)
200 /* NOTE: we don't care if we couldn't create the thread if there is at
201 * least one other available to process the request */
202 if ((num_workers
> 0) && (status
!= STATUS_SUCCESS
))
203 status
= STATUS_SUCCESS
;
206 if (status
!= STATUS_SUCCESS
)
208 RtlEnterCriticalSection(&threadpool_cs
);
210 interlocked_dec(&num_work_items
);
211 list_remove(&work_item
->entry
);
212 RtlFreeHeap(GetProcessHeap(), 0, work_item
);
214 RtlLeaveCriticalSection(&threadpool_cs
);
219 return STATUS_SUCCESS
;