1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using Microsoft.Win32.SafeHandles;
6 using System.ComponentModel;
7 
8 namespace System.Diagnostics
9 {
10     public partial class ProcessThread
11     {
12         /// <summary>Sets the processor that this thread would ideally like to run on.</summary>
13         public int IdealProcessor
14         {
15             set
16             {
17                 using (SafeThreadHandle threadHandle = OpenThreadHandle(Interop.Kernel32.ThreadOptions.THREAD_SET_INFORMATION))
18                 {
19                     if (Interop.Kernel32.SetThreadIdealProcessor(threadHandle, value) < 0)
20                     {
21                         throw new Win32Exception();
22                     }
23                 }
24             }
25         }
26 
27         /// <summary>
28         /// Resets the ideal processor so there is no ideal processor for this thread (e.g.
29         /// any processor is ideal).
30         /// </summary>
ResetIdealProcessor()31         public void ResetIdealProcessor()
32         {
33             // MAXIMUM_PROCESSORS == 32 on 32-bit or 64 on 64-bit, and means the thread has no preferred processor
34             int MAXIMUM_PROCESSORS = IntPtr.Size == 4 ? 32 : 64;
35             IdealProcessor = MAXIMUM_PROCESSORS;
36         }
37 
38         /// <summary>
39         /// Returns or sets whether this thread would like a priority boost if the user interacts
40         /// with user interface associated with this thread.
41         /// </summary>
42         private bool PriorityBoostEnabledCore
43         {
44             get
45             {
46                 using (SafeThreadHandle threadHandle = OpenThreadHandle(Interop.Kernel32.ThreadOptions.THREAD_QUERY_INFORMATION))
47                 {
48                     bool disabled;
49                     if (!Interop.Kernel32.GetThreadPriorityBoost(threadHandle, out disabled))
50                     {
51                         throw new Win32Exception();
52                     }
53                     return !disabled;
54                 }
55             }
56             set
57             {
58                 using (SafeThreadHandle threadHandle = OpenThreadHandle(Interop.Kernel32.ThreadOptions.THREAD_SET_INFORMATION))
59                 {
60                     if (!Interop.Kernel32.SetThreadPriorityBoost(threadHandle, !value))
61                         throw new Win32Exception();
62                 }
63             }
64         }
65 
66         /// <summary>
67         /// Returns or sets the priority level of the associated thread.  The priority level is
68         /// not an absolute level, but instead contributes to the actual thread priority by
69         /// considering the priority class of the process.
70         /// </summary>
71         private ThreadPriorityLevel PriorityLevelCore
72         {
73             get
74             {
75                 using (SafeThreadHandle threadHandle = OpenThreadHandle(Interop.Kernel32.ThreadOptions.THREAD_QUERY_INFORMATION))
76                 {
77                     int value = Interop.Kernel32.GetThreadPriority(threadHandle);
78                     if (value == 0x7fffffff)
79                     {
80                         throw new Win32Exception();
81                     }
82                     return (ThreadPriorityLevel)value;
83                 }
84             }
85             set
86             {
87                 using (SafeThreadHandle threadHandle = OpenThreadHandle(Interop.Kernel32.ThreadOptions.THREAD_SET_INFORMATION))
88                 {
89                     if (!Interop.Kernel32.SetThreadPriority(threadHandle, (int)value))
90                     {
91                         throw new Win32Exception();
92                     }
93                 }
94             }
95         }
96 
97         /// <summary>
98         /// Sets which processors the associated thread is allowed to be scheduled to run on.
99         /// Each processor is represented as a bit: bit 0 is processor one, bit 1 is processor
100         /// two, etc.  For example, the value 1 means run on processor one, 2 means run on
101         /// processor two, 3 means run on processor one or two.
102         /// </summary>
103         public IntPtr ProcessorAffinity
104         {
105             set
106             {
107                 using (SafeThreadHandle threadHandle = OpenThreadHandle(Interop.Kernel32.ThreadOptions.THREAD_SET_INFORMATION | Interop.Kernel32.ThreadOptions.THREAD_QUERY_INFORMATION))
108                 {
109                     if (Interop.Kernel32.SetThreadAffinityMask(threadHandle, value) == IntPtr.Zero)
110                     {
111                         throw new Win32Exception();
112                     }
113                 }
114             }
115         }
116 
117         /// <summary>
118         /// Returns the amount of time the thread has spent running code inside the operating
119         /// system core.
120         /// </summary>
121         public TimeSpan PrivilegedProcessorTime
122         {
123             get { return GetThreadTimes().PrivilegedProcessorTime; }
124         }
125 
126         /// <summary>Returns the time the associated thread was started.</summary>
127         public DateTime StartTime
128         {
129             get { return GetThreadTimes().StartTime; }
130         }
131 
132         /// <summary>
133         /// Returns the amount of time the associated thread has spent utilizing the CPU.
134         /// It is the sum of the System.Diagnostics.ProcessThread.UserProcessorTime and
135         /// System.Diagnostics.ProcessThread.PrivilegedProcessorTime.
136         /// </summary>
137         public TimeSpan TotalProcessorTime
138         {
139             get { return GetThreadTimes().TotalProcessorTime; }
140         }
141 
142         /// <summary>
143         /// Returns the amount of time the associated thread has spent running code
144         /// inside the application (not the operating system core).
145         /// </summary>
146         public TimeSpan UserProcessorTime
147         {
148             get { return GetThreadTimes().UserProcessorTime; }
149         }
150 
151         // -----------------------------
152         // ---- PAL layer ends here ----
153         // -----------------------------
154 
155         /// <summary>Gets timing information for the thread.</summary>
GetThreadTimes()156         private ProcessThreadTimes GetThreadTimes()
157         {
158             using (SafeThreadHandle threadHandle = OpenThreadHandle(Interop.Kernel32.ThreadOptions.THREAD_QUERY_INFORMATION))
159             {
160                 var threadTimes = new ProcessThreadTimes();
161                 if (!Interop.Kernel32.GetThreadTimes(threadHandle,
162                     out threadTimes._create, out threadTimes._exit,
163                     out threadTimes._kernel, out threadTimes._user))
164                 {
165                     throw new Win32Exception();
166                 }
167                 return threadTimes;
168             }
169         }
170 
171         /// <summary>Open a handle to the thread.</summary>
OpenThreadHandle(int access)172         private SafeThreadHandle OpenThreadHandle(int access)
173         {
174             EnsureState(State.IsLocal);
175             return ProcessManager.OpenThread((int)_threadInfo._threadId, access);
176         }
177     }
178 }
179