Standardize comment headers. Patch by Trevor McCort
[reactos.git] / reactos / 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 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 * Skywing (skywing@valhallalegends.com)
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #include <internal/debug.h>
16
17 /* GLOBALS *****************************************************************/
18
19 /*
20 * FIXME:
21 * Remove the Implemented value if all functions are implemented.
22 */
23
24 static const struct
25 {
26 BOOLEAN Implemented;
27 ULONG Size;
28 } QueryInformationData[MaxThreadInfoClass + 1] =
29 {
30 {TRUE, sizeof(THREAD_BASIC_INFORMATION)}, // ThreadBasicInformation
31 {TRUE, sizeof(KERNEL_USER_TIMES)}, // ThreadTimes
32 {TRUE, 0}, // ThreadPriority
33 {TRUE, 0}, // ThreadBasePriority
34 {TRUE, 0}, // ThreadAffinityMask
35 {TRUE, 0}, // ThreadImpersonationToken
36 {FALSE, 0}, // ThreadDescriptorTableEntry
37 {TRUE, 0}, // ThreadEnableAlignmentFaultFixup
38 {TRUE, 0}, // ThreadEventPair
39 {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress
40 {TRUE, 0}, // ThreadZeroTlsCell
41 {TRUE, sizeof(LARGE_INTEGER)}, // ThreadPerformanceCount
42 {TRUE, sizeof(BOOLEAN)}, // ThreadAmILastThread
43 {TRUE, 0}, // ThreadIdealProcessor
44 {FALSE, 0}, // ThreadPriorityBoost
45 {TRUE, 0}, // ThreadSetTlsArrayAddress
46 {FALSE, 0}, // ThreadIsIoPending
47 {TRUE, 0} // ThreadHideFromDebugger
48 };
49
50 static const struct
51 {
52 BOOLEAN Implemented;
53 ULONG Size;
54 } SetInformationData[MaxThreadInfoClass + 1] =
55 {
56 {TRUE, 0}, // ThreadBasicInformation
57 {TRUE, 0}, // ThreadTimes
58 {TRUE, sizeof(KPRIORITY)}, // ThreadPriority
59 {TRUE, sizeof(LONG)}, // ThreadBasePriority
60 {TRUE, sizeof(KAFFINITY)}, // ThreadAffinityMask
61 {TRUE, sizeof(HANDLE)}, // ThreadImpersonationToken
62 {TRUE, 0}, // ThreadDescriptorTableEntry
63 {FALSE, 0}, // ThreadEnableAlignmentFaultFixup
64 #ifdef _ENABLE_THRDEVTPAIR
65 {TRUE, sizeof(HANDLE)}, // ThreadEventPair
66 #else
67 {FALSE, 0}, // ThreadEventPair
68 #endif
69 {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress
70 {FALSE, 0}, // ThreadZeroTlsCell
71 {TRUE, 0}, // ThreadPerformanceCount
72 {TRUE, 0}, // ThreadAmILastThread
73 {FALSE, 0}, // ThreadIdealProcessor
74 {FALSE, 0}, // ThreadPriorityBoost
75 {FALSE, 0}, // ThreadSetTlsArrayAddress
76 {TRUE, 0}, // ThreadIsIoPending
77 {FALSE, 0} // ThreadHideFromDebugger
78 };
79
80 /* FUNCTIONS *****************************************************************/
81
82 /*
83 * @unimplemented
84 */
85 NTSTATUS STDCALL
86 NtSetInformationThread (IN HANDLE ThreadHandle,
87 IN THREADINFOCLASS ThreadInformationClass,
88 IN PVOID ThreadInformation,
89 IN ULONG ThreadInformationLength)
90 {
91 PETHREAD Thread;
92 NTSTATUS Status;
93 union
94 {
95 KPRIORITY Priority;
96 LONG Increment;
97 KAFFINITY Affinity;
98 HANDLE Handle;
99 PVOID Address;
100 }u;
101
102 if (ThreadInformationClass <= MaxThreadInfoClass &&
103 !SetInformationData[ThreadInformationClass].Implemented)
104 {
105 return STATUS_NOT_IMPLEMENTED;
106 }
107 if (ThreadInformationClass > MaxThreadInfoClass ||
108 SetInformationData[ThreadInformationClass].Size == 0)
109 {
110 return STATUS_INVALID_INFO_CLASS;
111 }
112 if (ThreadInformationLength != SetInformationData[ThreadInformationClass].Size)
113 {
114 return STATUS_INFO_LENGTH_MISMATCH;
115 }
116
117 Status = ObReferenceObjectByHandle (ThreadHandle,
118 THREAD_SET_INFORMATION,
119 PsThreadType,
120 ExGetPreviousMode (),
121 (PVOID*)&Thread,
122 NULL);
123 if (!NT_SUCCESS(Status))
124 {
125 return Status;
126 }
127
128 Status = MmCopyFromCaller(&u.Priority,
129 ThreadInformation,
130 SetInformationData[ThreadInformationClass].Size);
131 if (NT_SUCCESS(Status))
132 {
133 switch (ThreadInformationClass)
134 {
135 case ThreadPriority:
136 if (u.Priority < LOW_PRIORITY || u.Priority >= MAXIMUM_PRIORITY)
137 {
138 Status = STATUS_INVALID_PARAMETER;
139 break;
140 }
141 KeSetPriorityThread(&Thread->Tcb, u.Priority);
142 break;
143
144 case ThreadBasePriority:
145 KeSetBasePriorityThread (&Thread->Tcb, u.Increment);
146 break;
147
148 case ThreadAffinityMask:
149 Status = KeSetAffinityThread(&Thread->Tcb, u.Affinity);
150 break;
151
152 case ThreadImpersonationToken:
153 Status = PsAssignImpersonationToken (Thread, u.Handle);
154 break;
155
156 #ifdef _ENABLE_THRDEVTPAIR
157 case ThreadEventPair:
158 {
159 PKEVENT_PAIR EventPair;
160
161 Status = ObReferenceObjectByHandle(u.Handle,
162 STANDARD_RIGHTS_ALL,
163 ExEventPairObjectType,
164 ExGetPreviousMode(),
165 (PVOID*)&EventPair,
166 NULL);
167 if (NT_SUCCESS(Status))
168 {
169 ExpSwapThreadEventPair(Thread, EventPair); /* Note that the extra reference is kept intentionally */
170 }
171 break;
172 }
173 #endif /* _ENABLE_THRDEVTPAIR */
174
175 case ThreadQuerySetWin32StartAddress:
176 Thread->Win32StartAddress = u.Address;
177 break;
178
179 default:
180 /* Shoult never occure if the data table is correct */
181 KEBUGCHECK(0);
182 }
183 }
184 ObDereferenceObject (Thread);
185
186 return Status;
187 }
188
189 /*
190 * @implemented
191 */
192 NTSTATUS STDCALL
193 NtQueryInformationThread (IN HANDLE ThreadHandle,
194 IN THREADINFOCLASS ThreadInformationClass,
195 OUT PVOID ThreadInformation,
196 IN ULONG ThreadInformationLength,
197 OUT PULONG ReturnLength OPTIONAL)
198 {
199 PETHREAD Thread;
200 NTSTATUS Status;
201 union
202 {
203 THREAD_BASIC_INFORMATION TBI;
204 KERNEL_USER_TIMES TTI;
205 PVOID Address;
206 LARGE_INTEGER Count;
207 BOOLEAN Last;
208 }u;
209
210 if (ThreadInformationClass <= MaxThreadInfoClass &&
211 !QueryInformationData[ThreadInformationClass].Implemented)
212 {
213 return STATUS_NOT_IMPLEMENTED;
214 }
215 if (ThreadInformationClass > MaxThreadInfoClass ||
216 QueryInformationData[ThreadInformationClass].Size == 0)
217 {
218 return STATUS_INVALID_INFO_CLASS;
219 }
220 if (ThreadInformationLength != QueryInformationData[ThreadInformationClass].Size)
221 {
222 return STATUS_INFO_LENGTH_MISMATCH;
223 }
224
225 Status = ObReferenceObjectByHandle(ThreadHandle,
226 THREAD_QUERY_INFORMATION,
227 PsThreadType,
228 ExGetPreviousMode(),
229 (PVOID*)&Thread,
230 NULL);
231 if (!NT_SUCCESS(Status))
232 {
233 return Status;
234 }
235
236 switch (ThreadInformationClass)
237 {
238 case ThreadBasicInformation:
239 /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
240 * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is
241 * 0. So do the conversion here:
242 * -Gunnar */
243 u.TBI.ExitStatus = (Thread->ExitStatus == 0) ? STATUS_PENDING : Thread->ExitStatus;
244 u.TBI.TebBaseAddress = Thread->Tcb.Teb;
245 u.TBI.ClientId = Thread->Cid;
246 u.TBI.AffinityMask = Thread->Tcb.Affinity;
247 u.TBI.Priority = Thread->Tcb.Priority;
248 u.TBI.BasePriority = Thread->Tcb.BasePriority;
249 break;
250
251 case ThreadTimes:
252 u.TTI.KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL;
253 u.TTI.UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL;
254 u.TTI.CreateTime = Thread->CreateTime;
255 /*This works*/
256 u.TTI.ExitTime = Thread->ExitTime;
257 break;
258
259 case ThreadQuerySetWin32StartAddress:
260 u.Address = Thread->Win32StartAddress;
261 break;
262
263 case ThreadPerformanceCount:
264 /* Nebbett says this class is always zero */
265 u.Count.QuadPart = 0;
266 break;
267
268 case ThreadAmILastThread:
269 if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink ==
270 &Thread->ThreadsProcess->ThreadListHead)
271 {
272 u.Last = TRUE;
273 }
274 else
275 {
276 u.Last = FALSE;
277 }
278 break;
279 default:
280 /* Shoult never occure if the data table is correct */
281 KEBUGCHECK(0);
282 }
283 if (QueryInformationData[ThreadInformationClass].Size)
284 {
285 Status = MmCopyToCaller(ThreadInformation,
286 &u.TBI,
287 QueryInformationData[ThreadInformationClass].Size);
288 }
289 if (ReturnLength)
290 {
291 NTSTATUS Status2;
292 static ULONG Null = 0;
293 Status2 = MmCopyToCaller(ReturnLength,
294 NT_SUCCESS(Status) ? &QueryInformationData[ThreadInformationClass].Size : &Null,
295 sizeof(ULONG));
296 if (NT_SUCCESS(Status))
297 {
298 Status = Status2;
299 }
300 }
301
302 ObDereferenceObject(Thread);
303 return(Status);
304 }
305
306
307 VOID
308 KeSetPreviousMode (ULONG Mode)
309 {
310 PsGetCurrentThread()->Tcb.PreviousMode = (UCHAR)Mode;
311 }
312
313
314 /*
315 * @implemented
316 */
317 KPROCESSOR_MODE STDCALL
318 KeGetPreviousMode (VOID)
319 {
320 return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode;
321 }
322
323
324 /*
325 * @implemented
326 */
327 KPROCESSOR_MODE STDCALL
328 ExGetPreviousMode (VOID)
329 {
330 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
331 }
332
333 /* EOF */