update for HEAD-2003091401
[reactos.git] / ntoskrnl / ke / queue.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
4  *
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.
9  *
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.
14  *
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.
18  */
19 /* $Id$
20  *
21  * PROJECT:         ReactOS kernel
22  * FILE:            ntoskrnl/ke/queue.c
23  * PURPOSE:         Implements kernel queues
24  * PROGRAMMER:      Eric Kohl (ekohl@rz-online.de)
25  * UPDATE HISTORY:
26  *                  Created 04/01/2002
27  */
28
29 /* INCLUDES *****************************************************************/
30
31 #include <ddk/ntddk.h>
32 #include <ntos.h>
33 #include <internal/ke.h>
34 #include <internal/id.h>
35 #include <internal/ps.h>
36
37 #define NDEBUG
38 #include <internal/debug.h>
39
40 /* FUNCTIONS *****************************************************************/
41
42 /*
43  * @implemented
44  */
45 VOID STDCALL
46 KeInitializeQueue(IN PKQUEUE Queue,
47                   IN ULONG Count OPTIONAL)
48 {
49   KeInitializeDispatcherHeader(&Queue->Header,
50                                InternalQueueType,
51                                sizeof(KQUEUE)/sizeof(ULONG),
52                                0);
53   InitializeListHead(&Queue->EntryListHead);
54   InitializeListHead(&Queue->ThreadListHead);
55   Queue->CurrentCount = 0;
56   Queue->MaximumCount = (Count == 0) ? (ULONG) KeNumberProcessors : Count;
57 }
58
59
60 /*
61  * @implemented
62  */
63 LONG STDCALL
64 KeReadStateQueue(IN PKQUEUE Queue)
65 {
66   return(Queue->Header.SignalState);
67 }
68
69
70 LONG STDCALL
71 KiInsertQueue(
72    IN PKQUEUE Queue,
73    IN PLIST_ENTRY Entry,
74    BOOLEAN Head
75    )
76 {
77    ULONG InitialState;
78   
79    DPRINT("KiInsertQueue(Queue %x, Entry %x)\n", Queue, Entry);
80    
81    KeAcquireDispatcherDatabaseLock(FALSE);
82    
83    InitialState = Queue->Header.SignalState;
84    Queue->Header.SignalState++;
85    
86    if (Head)
87    {
88       InsertHeadList(&Queue->EntryListHead, Entry);
89    }
90    else
91    {
92       InsertTailList(&Queue->EntryListHead, Entry);
93    }
94
95    if (Queue->CurrentCount < Queue->MaximumCount && InitialState == 0)
96    {
97       KeDispatcherObjectWake(&Queue->Header);
98    }
99
100    KeReleaseDispatcherDatabaseLock(FALSE);
101    return InitialState;
102 }
103
104
105
106 /*
107  * @implemented
108  */
109 LONG STDCALL
110 KeInsertHeadQueue(IN PKQUEUE Queue,
111                   IN PLIST_ENTRY Entry)
112 {
113    return KiInsertQueue(Queue,Entry,TRUE);
114 }
115
116
117 /*
118  * @implemented
119  */
120 LONG STDCALL
121 KeInsertQueue(IN PKQUEUE Queue,
122               IN PLIST_ENTRY Entry)
123 {
124    return KiInsertQueue(Queue,Entry,FALSE);
125 }
126
127
128 /*
129  * @implemented
130  */
131 PLIST_ENTRY STDCALL
132 KeRemoveQueue(IN PKQUEUE Queue,
133               IN KPROCESSOR_MODE WaitMode,
134               IN PLARGE_INTEGER Timeout OPTIONAL)
135 {
136    PLIST_ENTRY ListEntry;
137    NTSTATUS Status;
138    PKTHREAD Thread = KeGetCurrentThread();
139
140    KeAcquireDispatcherDatabaseLock(FALSE);
141
142    //assiciate new thread with queue?
143    if (Thread->Queue != Queue)
144    {
145       //remove association from other queue
146       if (!IsListEmpty(&Thread->QueueListEntry))
147       {
148          RemoveEntryList(&Thread->QueueListEntry);
149       }
150
151       //associate with this queue
152       InsertHeadList(&Queue->ThreadListHead, &Thread->QueueListEntry);
153       Queue->CurrentCount++;
154       Thread->Queue = Queue;
155    }
156    
157    if (Queue->CurrentCount <= Queue->MaximumCount && !IsListEmpty(&Queue->EntryListHead))
158    {
159       ListEntry = RemoveHeadList(&Queue->EntryListHead);
160       Queue->Header.SignalState--;
161       KeReleaseDispatcherDatabaseLock(FALSE);
162       return ListEntry;
163    }
164
165    //need to wait for it...
166    KeReleaseDispatcherDatabaseLock(FALSE);
167
168    Status = KeWaitForSingleObject(Queue,
169                                   WrQueue,
170                                   WaitMode,
171                                   TRUE,//Alertable,
172                                   Timeout);
173
174    if (Status == STATUS_TIMEOUT || Status == STATUS_USER_APC)
175    {
176       return (PVOID)Status;
177    }
178    else
179    {
180       KeAcquireDispatcherDatabaseLock(FALSE);
181       ListEntry = RemoveHeadList(&Queue->EntryListHead);
182       KeReleaseDispatcherDatabaseLock(FALSE);
183       return ListEntry;
184    }
185
186 }
187
188
189 /*
190  * @implemented
191  */
192 PLIST_ENTRY STDCALL
193 KeRundownQueue(IN PKQUEUE Queue)
194 {
195    PLIST_ENTRY EnumEntry;
196    PKTHREAD Thread;
197
198    DPRINT("KeRundownQueue(Queue %x)\n", Queue);
199
200    //FIXME: should we wake thread waiting on a queue? 
201
202    KeAcquireDispatcherDatabaseLock(FALSE);
203
204    // Clear Queue and QueueListEntry members of all threads associated with this queue
205    while (!IsListEmpty(&Queue->ThreadListHead))
206    {
207       EnumEntry = RemoveHeadList(&Queue->ThreadListHead);
208       InitializeListHead(EnumEntry);
209       Thread = CONTAINING_RECORD(EnumEntry, KTHREAD, QueueListEntry);
210       Thread->Queue = NULL;
211    }
212
213    if (!IsListEmpty(&Queue->EntryListHead))
214       EnumEntry = Queue->EntryListHead.Flink;
215    else
216       EnumEntry = NULL;
217
218    KeReleaseDispatcherDatabaseLock(FALSE);
219
220    return EnumEntry;
221 }
222
223 /* EOF */