update for HEAD-2003091401
[reactos.git] / ntoskrnl / ps / suspend.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 1998, 1999, 2000, 2001 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/ps/suspend.c
23  * PURPOSE:                Thread managment
24  * PROGRAMMER:             David Welch (welch@mcmail.com)
25  */
26
27 /* INCLUDES ******************************************************************/
28
29 #include <ddk/ntddk.h>
30 #include <internal/ke.h>
31 #include <internal/ob.h>
32 #include <internal/ps.h>
33 #include <internal/ob.h>
34
35 #define NDEBUG
36 #include <internal/debug.h>
37
38 /* NOTES **********************************************************************
39  *
40  */
41
42 /* GLOBALS *******************************************************************/
43
44 static FAST_MUTEX SuspendMutex;
45
46 /* FUNCTIONS *****************************************************************/
47
48 VOID STDCALL
49 PiSuspendThreadRundownRoutine(PKAPC Apc)
50 {
51 }
52
53
54 VOID STDCALL
55 PiSuspendThreadKernelRoutine(PKAPC Apc,
56                              PKNORMAL_ROUTINE* NormalRoutine,
57                              PVOID* NormalContext,
58                              PVOID* SystemArgument1,
59                              PVOID* SystemArguemnt2)
60 {
61 }
62
63
64 VOID STDCALL
65 PiSuspendThreadNormalRoutine(PVOID NormalContext,
66                              PVOID SystemArgument1,
67                              PVOID SystemArgument2)
68 {
69   PETHREAD CurrentThread = PsGetCurrentThread();
70   while (CurrentThread->Tcb.SuspendCount > 0)
71     {
72       KeWaitForSingleObject(&CurrentThread->Tcb.SuspendSemaphore,
73                             0,
74                             UserMode,
75                             TRUE,
76                             NULL);
77     }
78 }
79
80
81 NTSTATUS
82 PsResumeThread(PETHREAD Thread, PULONG SuspendCount)
83 {
84   ExAcquireFastMutex(&SuspendMutex);
85   if (SuspendCount != NULL)
86     {
87       *SuspendCount = Thread->Tcb.SuspendCount;
88     }
89   if (Thread->Tcb.SuspendCount > 0)
90     {
91       Thread->Tcb.SuspendCount--;
92       if (Thread->Tcb.SuspendCount == 0)
93         {
94           KeReleaseSemaphore(&Thread->Tcb.SuspendSemaphore, IO_NO_INCREMENT, 
95                              1, FALSE);
96         }      
97     }
98   ExReleaseFastMutex(&SuspendMutex);
99   return(STATUS_SUCCESS);
100 }
101
102
103 NTSTATUS
104 PsSuspendThread(PETHREAD Thread, PULONG PreviousSuspendCount)
105 {
106   ULONG OldValue;
107
108   ExAcquireFastMutex(&SuspendMutex);
109   OldValue = Thread->Tcb.SuspendCount;
110   Thread->Tcb.SuspendCount++;
111   if (!Thread->Tcb.SuspendApc.Inserted)
112     {
113       if (!KeInsertQueueApc(&Thread->Tcb.SuspendApc,
114                             NULL,
115                             NULL,
116                             IO_NO_INCREMENT))
117         {
118           Thread->Tcb.SuspendCount--;
119           ExReleaseFastMutex(&SuspendMutex);
120           return(STATUS_THREAD_IS_TERMINATING);
121         }
122     }
123   ExReleaseFastMutex(&SuspendMutex);
124   if (PreviousSuspendCount != NULL)
125     {
126       *PreviousSuspendCount = OldValue;
127     }
128   return(STATUS_SUCCESS);
129 }
130
131
132 NTSTATUS STDCALL
133 NtResumeThread(IN HANDLE ThreadHandle,
134                IN PULONG SuspendCount)
135 /*
136  * FUNCTION: Decrements a thread's resume count
137  * ARGUMENTS: 
138  *        ThreadHandle = Handle to the thread that should be resumed
139  *        ResumeCount =  The resulting resume count.
140  * RETURNS: Status
141  */
142 {
143   PETHREAD Thread;
144   NTSTATUS Status;
145   ULONG Count;
146
147   DPRINT("NtResumeThead(ThreadHandle %lx  SuspendCount %p)\n",
148          ThreadHandle, SuspendCount);
149
150   Status = ObReferenceObjectByHandle(ThreadHandle,
151                                      THREAD_SUSPEND_RESUME,
152                                      PsThreadType,
153                                      UserMode,
154                                      (PVOID*)&Thread,
155                                      NULL);
156   if (!NT_SUCCESS(Status))
157     {
158       return(Status);
159     }
160
161   Status = PsResumeThread(Thread, &Count);
162   if (SuspendCount != NULL)
163     {
164       *SuspendCount = Count;
165     }
166
167   ObDereferenceObject((PVOID)Thread);
168
169   return(STATUS_SUCCESS);
170 }
171
172
173 NTSTATUS STDCALL
174 NtSuspendThread(IN HANDLE ThreadHandle,
175                 IN PULONG PreviousSuspendCount)
176 /*
177  * FUNCTION: Increments a thread's suspend count
178  * ARGUMENTS: 
179  *        ThreadHandle = Handle to the thread that should be resumed
180  *        PreviousSuspendCount =  The resulting/previous suspend count.
181  * REMARK:
182  *        A thread will be suspended if its suspend count is greater than 0. 
183  *        This procedure maps to the win32 SuspendThread function. ( 
184  *        documentation about the the suspend count can be found here aswell )
185  *        The suspend count is not increased if it is greater than 
186  *        MAXIMUM_SUSPEND_COUNT.
187  * RETURNS: Status
188  */
189 {
190   PETHREAD Thread;
191   NTSTATUS Status;
192   ULONG Count;
193
194   Status = ObReferenceObjectByHandle(ThreadHandle,
195                                      THREAD_SUSPEND_RESUME,
196                                      PsThreadType,
197                                      UserMode,
198                                      (PVOID*)&Thread,
199                                      NULL);
200   if (!NT_SUCCESS(Status))
201     {
202       return(Status);
203     }
204
205   Status = PsSuspendThread(Thread, &Count);
206   if (PreviousSuspendCount != NULL)
207     {
208       *PreviousSuspendCount = Count;
209     }
210
211   ObDereferenceObject((PVOID)Thread);
212
213   return(STATUS_SUCCESS);
214 }
215
216 VOID
217 PsInitialiseSuspendImplementation(VOID)
218 {
219   ExInitializeFastMutex(&SuspendMutex);
220 }
221
222 /* EOF */