c9ca051d48f93be1596713e5cbb3cd2085ec5f1f
[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 PAGED_CODE();
103
104 if (ThreadInformationClass <= MaxThreadInfoClass &&
105 !SetInformationData[ThreadInformationClass].Implemented)
106 {
107 return STATUS_NOT_IMPLEMENTED;
108 }
109 if (ThreadInformationClass > MaxThreadInfoClass ||
110 SetInformationData[ThreadInformationClass].Size == 0)
111 {
112 return STATUS_INVALID_INFO_CLASS;
113 }
114 if (ThreadInformationLength != SetInformationData[ThreadInformationClass].Size)
115 {
116 return STATUS_INFO_LENGTH_MISMATCH;
117 }
118
119 Status = ObReferenceObjectByHandle (ThreadHandle,
120 THREAD_SET_INFORMATION,
121 PsThreadType,
122 ExGetPreviousMode (),
123 (PVOID*)&Thread,
124 NULL);
125 if (!NT_SUCCESS(Status))
126 {
127 return Status;
128 }
129
130 Status = MmCopyFromCaller(&u.Priority,
131 ThreadInformation,
132 SetInformationData[ThreadInformationClass].Size);
133 if (NT_SUCCESS(Status))
134 {
135 switch (ThreadInformationClass)
136 {
137 case ThreadPriority:
138 if (u.Priority < LOW_PRIORITY || u.Priority >= MAXIMUM_PRIORITY)
139 {
140 Status = STATUS_INVALID_PARAMETER;
141 break;
142 }
143 KeSetPriorityThread(&Thread->Tcb, u.Priority);
144 break;
145
146 case ThreadBasePriority:
147 KeSetBasePriorityThread (&Thread->Tcb, u.Increment);
148 break;
149
150 case ThreadAffinityMask:
151 Status = KeSetAffinityThread(&Thread->Tcb, u.Affinity);
152 break;
153
154 case ThreadImpersonationToken:
155 Status = PsAssignImpersonationToken (Thread, u.Handle);
156 break;
157
158 #ifdef _ENABLE_THRDEVTPAIR
159 case ThreadEventPair:
160 {
161 PKEVENT_PAIR EventPair;
162
163 Status = ObReferenceObjectByHandle(u.Handle,
164 STANDARD_RIGHTS_ALL,
165 ExEventPairObjectType,
166 ExGetPreviousMode(),
167 (PVOID*)&EventPair,
168 NULL);
169 if (NT_SUCCESS(Status))
170 {
171 ExpSwapThreadEventPair(Thread, EventPair); /* Note that the extra reference is kept intentionally */
172 }
173 break;
174 }
175 #endif /* _ENABLE_THRDEVTPAIR */
176
177 case ThreadQuerySetWin32StartAddress:
178 Thread->Win32StartAddress = u.Address;
179 break;
180
181 default:
182 /* Shoult never occure if the data table is correct */
183 KEBUGCHECK(0);
184 }
185 }
186 ObDereferenceObject (Thread);
187
188 return Status;
189 }
190
191 /*
192 * @implemented
193 */
194 NTSTATUS STDCALL
195 NtQueryInformationThread (IN HANDLE ThreadHandle,
196 IN THREADINFOCLASS ThreadInformationClass,
197 OUT PVOID ThreadInformation,
198 IN ULONG ThreadInformationLength,
199 OUT PULONG ReturnLength OPTIONAL)
200 {
201 PETHREAD Thread;
202 NTSTATUS Status;
203 union
204 {
205 THREAD_BASIC_INFORMATION TBI;
206 KERNEL_USER_TIMES TTI;
207 PVOID Address;
208 LARGE_INTEGER Count;
209 BOOLEAN Last;
210 }u;
211
212 PAGED_CODE();
213
214 if (ThreadInformationClass <= MaxThreadInfoClass &&
215 !QueryInformationData[ThreadInformationClass].Implemented)
216 {
217 return STATUS_NOT_IMPLEMENTED;
218 }
219 if (ThreadInformationClass > MaxThreadInfoClass ||
220 QueryInformationData[ThreadInformationClass].Size == 0)
221 {
222 return STATUS_INVALID_INFO_CLASS;
223 }
224 if (ThreadInformationLength != QueryInformationData[ThreadInformationClass].Size)
225 {
226 return STATUS_INFO_LENGTH_MISMATCH;
227 }
228
229 Status = ObReferenceObjectByHandle(ThreadHandle,
230 THREAD_QUERY_INFORMATION,
231 PsThreadType,
232 ExGetPreviousMode(),
233 (PVOID*)&Thread,
234 NULL);
235 if (!NT_SUCCESS(Status))
236 {
237 return Status;
238 }
239
240 switch (ThreadInformationClass)
241 {
242 case ThreadBasicInformation:
243 /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
244 * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is
245 * 0. So do the conversion here:
246 * -Gunnar */
247 u.TBI.ExitStatus = (Thread->ExitStatus == 0) ? STATUS_PENDING : Thread->ExitStatus;
248 u.TBI.TebBaseAddress = Thread->Tcb.Teb;
249 u.TBI.ClientId = Thread->Cid;
250 u.TBI.AffinityMask = Thread->Tcb.Affinity;
251 u.TBI.Priority = Thread->Tcb.Priority;
252 u.TBI.BasePriority = Thread->Tcb.BasePriority;
253 break;
254
255 case ThreadTimes:
256 u.TTI.KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL;
257 u.TTI.UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL;
258 u.TTI.CreateTime = Thread->CreateTime;
259 /*This works*/
260 u.TTI.ExitTime = Thread->ExitTime;
261 break;
262
263 case ThreadQuerySetWin32StartAddress:
264 u.Address = Thread->Win32StartAddress;
265 break;
266
267 case ThreadPerformanceCount:
268 /* Nebbett says this class is always zero */
269 u.Count.QuadPart = 0;
270 break;
271
272 case ThreadAmILastThread:
273 if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink ==
274 &Thread->ThreadsProcess->ThreadListHead)
275 {
276 u.Last = TRUE;
277 }
278 else
279 {
280 u.Last = FALSE;
281 }
282 break;
283 default:
284 /* Shoult never occure if the data table is correct */
285 KEBUGCHECK(0);
286 }
287 if (QueryInformationData[ThreadInformationClass].Size)
288 {
289 Status = MmCopyToCaller(ThreadInformation,
290 &u.TBI,
291 QueryInformationData[ThreadInformationClass].Size);
292 }
293 if (ReturnLength)
294 {
295 NTSTATUS Status2;
296 static ULONG Null = 0;
297 Status2 = MmCopyToCaller(ReturnLength,
298 NT_SUCCESS(Status) ? &QueryInformationData[ThreadInformationClass].Size : &Null,
299 sizeof(ULONG));
300 if (NT_SUCCESS(Status))
301 {
302 Status = Status2;
303 }
304 }
305
306 ObDereferenceObject(Thread);
307 return(Status);
308 }
309
310
311 VOID
312 KeSetPreviousMode (ULONG Mode)
313 {
314 PsGetCurrentThread()->Tcb.PreviousMode = (UCHAR)Mode;
315 }
316
317
318 /*
319 * @implemented
320 */
321 KPROCESSOR_MODE STDCALL
322 KeGetPreviousMode (VOID)
323 {
324 return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode;
325 }
326
327
328 /*
329 * @implemented
330 */
331 KPROCESSOR_MODE STDCALL
332 ExGetPreviousMode (VOID)
333 {
334 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
335 }
336
337 /* EOF */