3 * Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/ke/queue.c
23 * PURPOSE: Implements kernel queues
24 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
29 /* INCLUDES *****************************************************************/
33 #include <internal/debug.h>
35 /* FUNCTIONS *****************************************************************/
42 KeInitializeQueue(IN PKQUEUE Queue
,
43 IN ULONG Count OPTIONAL
)
45 KeInitializeDispatcherHeader(&Queue
->Header
,
47 sizeof(KQUEUE
)/sizeof(ULONG
),
49 InitializeListHead(&Queue
->EntryListHead
);
50 InitializeListHead(&Queue
->ThreadListHead
);
51 Queue
->CurrentCount
= 0;
52 Queue
->MaximumCount
= (Count
== 0) ? (ULONG
) KeNumberProcessors
: Count
;
59 * Returns number of entries in the queue
62 KeReadStateQueue(IN PKQUEUE Queue
)
64 return(Queue
->Header
.SignalState
);
68 * Returns the previous number of entries in the queue
79 DPRINT("KiInsertQueue(Queue %x, Entry %x)\n", Queue
, Entry
);
81 InitialState
= Queue
->Header
.SignalState
;
85 InsertHeadList(&Queue
->EntryListHead
, Entry
);
89 InsertTailList(&Queue
->EntryListHead
, Entry
);
92 //inc. num entries in queue
93 Queue
->Header
.SignalState
++;
95 /* Why the KeGetCurrentThread()->Queue != Queue?
96 * KiInsertQueue might be called from an APC for the current thread.
99 if (Queue
->CurrentCount
< Queue
->MaximumCount
&&
100 !IsListEmpty(&Queue
->Header
.WaitListHead
) &&
101 KeGetCurrentThread()->Queue
!= Queue
)
103 KiDispatcherObjectWake(&Queue
->Header
, IO_NO_INCREMENT
);
115 KeInsertHeadQueue(IN PKQUEUE Queue
,
116 IN PLIST_ENTRY Entry
)
121 OldIrql
= KeAcquireDispatcherDatabaseLock();
122 Result
= KiInsertQueue(Queue
,Entry
,TRUE
);
123 KeReleaseDispatcherDatabaseLock(OldIrql
);
133 KeInsertQueue(IN PKQUEUE Queue
,
134 IN PLIST_ENTRY Entry
)
139 OldIrql
= KeAcquireDispatcherDatabaseLock();
140 Result
= KiInsertQueue(Queue
,Entry
,FALSE
);
141 KeReleaseDispatcherDatabaseLock(OldIrql
);
151 KeRemoveQueue(IN PKQUEUE Queue
,
152 IN KPROCESSOR_MODE WaitMode
,
153 IN PLARGE_INTEGER Timeout OPTIONAL
)
156 PLIST_ENTRY ListEntry
;
158 PKTHREAD Thread
= KeGetCurrentThread();
161 OldIrql
= KeAcquireDispatcherDatabaseLock ();
163 if (Thread
->Queue
!= Queue
)
166 * INVESTIGATE: What is the Thread->QueueListEntry used for? It's linked it into the
167 * Queue->ThreadListHead when the thread registers with the queue and unlinked when
168 * the thread registers with a new queue. The Thread->Queue already tells us what
169 * queue the thread is registered with.
173 //unregister thread from previous queue (if any)
176 RemoveEntryList(&Thread
->QueueListEntry
);
177 Thread
->Queue
->CurrentCount
--;
179 if (Thread
->Queue
->CurrentCount
< Thread
->Queue
->MaximumCount
&&
180 !IsListEmpty(&Thread
->Queue
->EntryListHead
))
182 KiDispatcherObjectWake(&Thread
->Queue
->Header
, 0);
186 // register thread with this queue
187 InsertTailList(&Queue
->ThreadListHead
, &Thread
->QueueListEntry
);
188 Thread
->Queue
= Queue
;
190 else /* if (Thread->Queue == Queue) */
192 //dec. num running threads
193 Queue
->CurrentCount
--;
201 if (Queue
->CurrentCount
< Queue
->MaximumCount
&& !IsListEmpty(&Queue
->EntryListHead
))
203 ListEntry
= RemoveHeadList(&Queue
->EntryListHead
);
204 //dec. num entries in queue
205 Queue
->Header
.SignalState
--;
206 //inc. num running threads
207 Queue
->CurrentCount
++;
209 KeReleaseDispatcherDatabaseLock(OldIrql
);
214 //inform KeWaitXxx that we are holding disp. lock
215 Thread
->WaitNext
= TRUE
;
216 Thread
->WaitIrql
= OldIrql
;
218 Status
= KeWaitForSingleObject(Queue
,
224 if (Status
== STATUS_TIMEOUT
|| Status
== STATUS_USER_APC
)
226 return (PVOID
)Status
;
229 OldIrql
= KeAcquireDispatcherDatabaseLock ();
239 KeRundownQueue(IN PKQUEUE Queue
)
241 PLIST_ENTRY EnumEntry
;
245 DPRINT("KeRundownQueue(Queue %x)\n", Queue
);
247 /* I'm just guessing how this should work:-/
251 OldIrql
= KeAcquireDispatcherDatabaseLock ();
253 //no thread must wait on queue at rundown
254 ASSERT(IsListEmpty(&Queue
->Header
.WaitListHead
));
256 // unlink threads and clear their Thread->Queue
257 while (!IsListEmpty(&Queue
->ThreadListHead
))
259 EnumEntry
= RemoveHeadList(&Queue
->ThreadListHead
);
260 Thread
= CONTAINING_RECORD(EnumEntry
, KTHREAD
, QueueListEntry
);
261 Thread
->Queue
= NULL
;
264 if (IsListEmpty(&Queue
->EntryListHead
))
270 EnumEntry
= Queue
->EntryListHead
.Flink
;
273 KeReleaseDispatcherDatabaseLock (OldIrql
);