:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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       KeInsertQueueApc(&Thread->Tcb.SuspendApc,
114                        NULL,
115                        NULL,
116                        0);
117     }
118   ExReleaseFastMutex(&SuspendMutex);
119   if (PreviousSuspendCount != NULL)
120     {
121       *PreviousSuspendCount = OldValue;
122     }
123   return(STATUS_SUCCESS);
124 }
125
126
127 NTSTATUS STDCALL
128 NtResumeThread(IN HANDLE ThreadHandle,
129                IN PULONG SuspendCount)
130 /*
131  * FUNCTION: Decrements a thread's resume count
132  * ARGUMENTS: 
133  *        ThreadHandle = Handle to the thread that should be resumed
134  *        ResumeCount =  The resulting resume count.
135  * RETURNS: Status
136  */
137 {
138   PETHREAD Thread;
139   NTSTATUS Status;
140   ULONG Count;
141
142   DPRINT("NtResumeThead(ThreadHandle %lx  SuspendCount %p)\n",
143          ThreadHandle, SuspendCount);
144
145   Status = ObReferenceObjectByHandle(ThreadHandle,
146                                      THREAD_SUSPEND_RESUME,
147                                      PsThreadType,
148                                      UserMode,
149                                      (PVOID*)&Thread,
150                                      NULL);
151   if (!NT_SUCCESS(Status))
152     {
153       return(Status);
154     }
155
156   Status = PsResumeThread(Thread, &Count);
157   if (SuspendCount != NULL)
158     {
159       *SuspendCount = Count;
160     }
161
162   ObDereferenceObject((PVOID)Thread);
163
164   return(STATUS_SUCCESS);
165 }
166
167
168 NTSTATUS STDCALL
169 NtSuspendThread(IN HANDLE ThreadHandle,
170                 IN PULONG PreviousSuspendCount)
171 /*
172  * FUNCTION: Increments a thread's suspend count
173  * ARGUMENTS: 
174  *        ThreadHandle = Handle to the thread that should be resumed
175  *        PreviousSuspendCount =  The resulting/previous suspend count.
176  * REMARK:
177  *        A thread will be suspended if its suspend count is greater than 0. 
178  *        This procedure maps to the win32 SuspendThread function. ( 
179  *        documentation about the the suspend count can be found here aswell )
180  *        The suspend count is not increased if it is greater than 
181  *        MAXIMUM_SUSPEND_COUNT.
182  * RETURNS: Status
183  */
184 {
185   PETHREAD Thread;
186   NTSTATUS Status;
187   ULONG Count;
188
189   Status = ObReferenceObjectByHandle(ThreadHandle,
190                                      THREAD_SUSPEND_RESUME,
191                                      PsThreadType,
192                                      UserMode,
193                                      (PVOID*)&Thread,
194                                      NULL);
195   if (!NT_SUCCESS(Status))
196     {
197       return(Status);
198     }
199
200   Status = PsSuspendThread(Thread, &Count);
201   if (PreviousSuspendCount != NULL)
202     {
203       *PreviousSuspendCount = Count;
204     }
205
206   ObDereferenceObject((PVOID)Thread);
207
208   return(STATUS_SUCCESS);
209 }
210
211 VOID
212 PsInitialiseSuspendImplementation(VOID)
213 {
214   ExInitializeFastMutex(&SuspendMutex);
215 }
216
217 /* EOF */