update for HEAD-2003091401
[reactos.git] / ntoskrnl / ps / tinfo.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/ps/tinfo.c
6  * PURPOSE:         Getting/setting thread information
7  * PROGRAMMER:      David Welch (welch@mcmail.com)
8  * UPDATE HISTORY:
9  *                  Created 22/05/98
10  *                  Updated 09/08/2003 by Skywing (skywing@valhallalegends.com)
11  *                   to suppport thread-eventpairs.
12  */
13
14 /* INCLUDES *****************************************************************/
15
16 #include <ddk/ntddk.h>
17 #include <internal/ps.h>
18 #include <internal/ex.h>
19 #include <internal/safe.h>
20
21 #include <internal/debug.h>
22
23 /* FUNCTIONS *****************************************************************/
24
25 NTSTATUS STDCALL 
26 NtSetInformationThread(HANDLE           ThreadHandle,
27                        THREADINFOCLASS  ThreadInformationClass,
28                        PVOID            ThreadInformation,
29                        ULONG ThreadInformationLength)
30 {
31    PETHREAD                     Thread;
32    NTSTATUS                     Status;
33    
34    Status = ObReferenceObjectByHandle(ThreadHandle,
35                                       THREAD_SET_INFORMATION,
36                                       PsThreadType,
37                                       ExGetPreviousMode(),
38                                       (PVOID*)&Thread,
39                                       NULL);
40    if (!NT_SUCCESS(Status))
41      {
42         return Status;
43      }
44    
45    switch (ThreadInformationClass)
46      {
47       case ThreadBasicInformation:
48         /* Can only be queried */
49         Status = STATUS_INVALID_INFO_CLASS;
50         break;
51         
52       case ThreadTimes:
53         /* Can only be queried */
54         Status = STATUS_INVALID_INFO_CLASS;
55         break;
56         
57       case ThreadPriority:
58           {
59             KPRIORITY Priority;
60             
61             if (ThreadInformationLength != sizeof(KPRIORITY))
62               {
63                 Status = STATUS_INFO_LENGTH_MISMATCH;
64                 break;
65               }
66             Priority = *(KPRIORITY*)ThreadInformation;
67             if (Priority < LOW_PRIORITY || Priority >= MAXIMUM_PRIORITY)
68               {
69                 Status = STATUS_INVALID_PARAMETER;
70                 break;
71               }
72             KeSetPriorityThread(&Thread->Tcb, Priority);
73             Status = STATUS_SUCCESS;
74             break;
75           }
76         
77       case ThreadBasePriority:
78         if (ThreadInformationLength != sizeof(ULONG))
79           {
80             Status = STATUS_INFO_LENGTH_MISMATCH;
81             break;
82           }
83         Status = MmCopyFromCaller(&(Thread->Tcb.BasePriority),
84                                   ThreadInformation,
85                                   sizeof(ULONG));
86         break;
87         
88       case ThreadAffinityMask:
89         Thread->Tcb.UserAffinity = *((PULONG)ThreadInformation);
90         break;
91         
92       case ThreadImpersonationToken:
93         {
94           HANDLE TokenHandle;
95
96           if (ThreadInformationLength != sizeof(HANDLE))
97             {
98               Status = STATUS_INFO_LENGTH_MISMATCH;
99               break;
100             }
101           TokenHandle = *((PHANDLE)ThreadInformation);
102           Status = PsAssignImpersonationToken(Thread, TokenHandle);
103           break;
104         }
105         
106       case ThreadDescriptorTableEntry:
107         /* Can only be queried */
108         Status = STATUS_INVALID_INFO_CLASS;
109         break;
110         
111       case ThreadEventPair:
112         {
113           PKEVENT_PAIR EventPair;
114
115           if (ThreadInformationLength != sizeof(HANDLE))
116             {
117               Status = STATUS_INFO_LENGTH_MISMATCH;
118               break;
119             }
120
121           if (ExGetPreviousMode() == UserMode) /* FIXME: Validate this for all infoclasses and system services */
122             {
123               DPRINT("NtSetInformationThread:ThreadEventPair: Checking user pointer %08x...\n", ThreadInformation);
124               ProbeForRead(ThreadInformation, sizeof(HANDLE), sizeof(HANDLE)); /* FIXME: This entire function should be
125                * wrapped in an SEH frame... return (NTSTATUS)GetExceptionCode() on exception */
126             }
127
128           Status = ObReferenceObjectByHandle(*(PHANDLE)ThreadInformation,
129                                              STANDARD_RIGHTS_ALL,
130                                              ExEventPairObjectType,
131                                              ExGetPreviousMode(),
132                                              (PVOID*)&EventPair,
133                                              NULL);
134
135           if (!NT_SUCCESS(Status))
136             {
137               break;
138             }
139
140           ExpSwapThreadEventPair(Thread, EventPair); /* Note that the extra reference is kept intentionally */
141           Status = STATUS_SUCCESS;
142           break;
143         }
144         
145       case ThreadQuerySetWin32StartAddress:
146         if (ThreadInformationLength != sizeof(ULONG))
147           {
148             Status = STATUS_INFO_LENGTH_MISMATCH;
149             break;
150           }
151         Thread->u2.Win32StartAddress = (PVOID)*((PULONG)ThreadInformation);
152         Status = STATUS_SUCCESS;
153         break;
154                 
155       case ThreadZeroTlsCell:
156         {
157           Status = STATUS_NOT_IMPLEMENTED;
158           break;
159         }
160         
161       case ThreadPerformanceCount:
162         /* Can only be queried */
163         Status = STATUS_INVALID_INFO_CLASS;
164         break;
165         
166       case ThreadAmILastThread:
167         /* Can only be queried */
168         Status = STATUS_INVALID_INFO_CLASS;
169         break;
170         
171      case ThreadIdealProcessor:
172        Status = STATUS_NOT_IMPLEMENTED;
173        break;
174        
175      case ThreadPriorityBoost:
176        Status = STATUS_NOT_IMPLEMENTED;
177        break;
178         
179      case ThreadSetTlsArrayAddress:
180        Status = STATUS_NOT_IMPLEMENTED;
181        break;
182
183      case ThreadIsIoPending:
184        /* Can only be queried */
185        Status = STATUS_INVALID_INFO_CLASS;
186        break;
187
188      case ThreadHideFromDebugger:
189        Status = STATUS_NOT_IMPLEMENTED;
190        break;
191
192       default:
193         Status = STATUS_UNSUCCESSFUL;
194      }
195    ObDereferenceObject(Thread);
196    return Status;
197 }
198
199
200 NTSTATUS STDCALL
201 NtQueryInformationThread (IN    HANDLE          ThreadHandle,
202                           IN    THREADINFOCLASS ThreadInformationClass,
203                           OUT   PVOID           ThreadInformation,
204                           IN    ULONG           ThreadInformationLength,
205                           OUT   PULONG          ReturnLength)
206 {
207    PETHREAD Thread;
208    NTSTATUS Status;
209
210    Status = ObReferenceObjectByHandle(ThreadHandle,
211                                       THREAD_QUERY_INFORMATION,
212                                       PsThreadType,
213                                       ExGetPreviousMode(),
214                                       (PVOID*)&Thread,
215                                       NULL);
216    if (!NT_SUCCESS(Status))
217      {
218         return Status;
219      }
220
221    switch (ThreadInformationClass)
222      {
223      case ThreadBasicInformation:
224        {
225          PTHREAD_BASIC_INFORMATION TBI;
226          
227          TBI = (PTHREAD_BASIC_INFORMATION)ThreadInformation;
228          
229          if (ThreadInformationLength != sizeof(THREAD_BASIC_INFORMATION))
230            {
231              Status = STATUS_INFO_LENGTH_MISMATCH;
232              break;
233            }
234          
235          TBI->ExitStatus = Thread->ExitStatus;
236          TBI->TebBaseAddress = Thread->Tcb.Teb;
237          TBI->ClientId = Thread->Cid;
238          TBI->AffinityMask = Thread->Tcb.Affinity;
239          TBI->Priority = Thread->Tcb.Priority;
240          TBI->BasePriority = Thread->Tcb.BasePriority;
241          Status = STATUS_SUCCESS;
242          break;
243        }
244        
245      case ThreadTimes:
246        Status = STATUS_NOT_IMPLEMENTED;
247        break;
248        
249      case ThreadPriority:
250        /* Can be set only */
251        Status = STATUS_INVALID_INFO_CLASS;
252        break;
253        
254      case ThreadBasePriority:
255        /* Can be set only */
256        Status = STATUS_INVALID_INFO_CLASS;
257        break;
258        
259      case ThreadAffinityMask:
260        /* Can be set only */
261        Status = STATUS_INVALID_INFO_CLASS;
262        break;
263
264      case ThreadImpersonationToken:
265        /* Can be set only */
266        Status = STATUS_INVALID_INFO_CLASS;
267        break;
268        
269      case ThreadDescriptorTableEntry:
270        /* Nebbett says nothing about this */
271        Status = STATUS_NOT_IMPLEMENTED;
272        break;
273
274      case ThreadEnableAlignmentFaultFixup:
275        /* Can be set only */
276        Status = STATUS_INVALID_INFO_CLASS;
277        break;
278        
279      case ThreadEventPair:
280        /* Can be set only */
281        Status = STATUS_INVALID_INFO_CLASS;
282        break;
283
284      case ThreadQuerySetWin32StartAddress:
285        if (ThreadInformationLength != sizeof(PVOID))
286          {
287            Status = STATUS_INFO_LENGTH_MISMATCH;
288            break;
289          }
290        *((PVOID*)ThreadInformation) = Thread->u2.Win32StartAddress;
291        Status = STATUS_SUCCESS;
292        break;
293
294      case ThreadZeroTlsCell:
295        /* Can only be set */
296        Status = STATUS_INVALID_INFO_CLASS;
297        break;
298
299      case ThreadPerformanceCount:
300        /* Nebbett says this class is always zero */
301        if (ThreadInformationLength != sizeof(LARGE_INTEGER))
302          {
303            Status = STATUS_INFO_LENGTH_MISMATCH;
304            break;
305          }
306        ((PLARGE_INTEGER)ThreadInformation)->QuadPart = 0;
307        Status = STATUS_SUCCESS;
308        break;
309
310      case ThreadAmILastThread:
311        {
312          if (ThreadInformationLength != sizeof(BOOLEAN))
313            {
314              Status = STATUS_INFO_LENGTH_MISMATCH;
315              break;
316            }
317          if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink ==
318              &Thread->ThreadsProcess->ThreadListHead)
319            {
320              *((PBOOLEAN)ThreadInformation) = TRUE;
321            }
322          else
323            {
324              *((PBOOLEAN)ThreadInformation) = FALSE;
325            }
326          Status = STATUS_SUCCESS;
327          break;
328        }
329
330      case ThreadIdealProcessor:
331        /* Can only be set */
332        Status = STATUS_INFO_LENGTH_MISMATCH;
333        break;
334
335      case ThreadPriorityBoost:
336        Status = STATUS_NOT_IMPLEMENTED;
337        break;
338
339      case ThreadSetTlsArrayAddress:
340        /* Can only be set */
341        Status = STATUS_INVALID_INFO_CLASS;
342        break;
343
344      case ThreadIsIoPending:
345        Status = STATUS_NOT_IMPLEMENTED;
346        break;
347        
348      case ThreadHideFromDebugger:
349        /* Can only be set */
350        Status = STATUS_INVALID_INFO_CLASS;
351        break;
352
353       default:
354         Status = STATUS_INVALID_INFO_CLASS;
355      }
356    ObDereferenceObject(Thread);
357    return(Status);
358 }
359
360 VOID KeSetPreviousMode(ULONG Mode)
361 {
362    PsGetCurrentThread()->Tcb.PreviousMode = Mode;
363 }
364
365 /*
366  * @implemented
367  */
368 ULONG STDCALL
369 KeGetPreviousMode (VOID)
370 {
371    return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode;
372 }
373
374 /*
375  * @implemented
376  */
377 ULONG STDCALL
378 ExGetPreviousMode (VOID)
379 {
380    return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode;
381 }
382
383 /* EOF */