forked from kolesnikovae/go-winjob
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlimits.go
More file actions
452 lines (381 loc) · 15 KB
/
Copy pathlimits.go
File metadata and controls
452 lines (381 loc) · 15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
//go:build windows
package winjob
import (
"time"
"github.com/aperturerobotics/go-winjob/jobapi"
)
// WithBreakawayOK allows any process associated with the job to create child
// processes that are not associated with the job, if the process created with
// CREATE_BREAKAWAY_FROM_JOB flag.
func WithBreakawayOK() Limit {
return LimitBreakawayOK
}
// WithSilentBreakawayOK allows any process associated with the job to create
// child processes that are not associated with the job. If the job is nested
// and its immediate job object allows breakaway, the child process breaks away
// from the immediate job object and from each job in the parent job chain,
// moving up the hierarchy until it reaches a job that does not permit breakaway.
// If the immediate job object does not allow breakaway, the child process does
// not break away even if jobs in its parent job chain allow it.
func WithSilentBreakawayOK() Limit {
return LimitSilentBreakawayOK
}
// WithDieOnUnhandledException forces a call to the SetErrorMode function with
// the SEM_NOGPFAULTERRORBOX flag for each process associated with the job.
//
// If an exception occurs and the system calls the UnhandledExceptionFilter
// function, the debugger will be given a chance to act. If there is no
// debugger, the functions returns EXCEPTION_EXECUTE_HANDLER. Normally, this
// will cause termination of the process with the exception code as the exit
// status.
func WithDieOnUnhandledException() Limit {
return LimitDieOnUnhandledException
}
// WithKillOnJobClose causes all processes associated with the job to terminate
// when the last handle to the job is closed.
func WithKillOnJobClose() Limit {
return LimitKillOnJobClose
}
// WithPreserveJobTime preserves any job time limits you previously set. As
// long as this limit is set, you can establish a per-job time limit once, then
// alter other limits in subsequent calls.
//
// This flag cannot be used with LimitJobMemory.
func WithPreserveJobTime() Limit {
return LimitPreserveJobTime
}
// WithSubsetAffinity allows processes to use a subset of the processor
// affinity for all processes associated with the job.
//
// This limit must be combined with LimitAffinity.
func WithSubsetAffinity() Limit {
return LimitSubsetAffinity
}
// WithAffinity causes all processes associated with the job to use the same
// processor affinity.
//
// The value specified must be a subset of the system affinity mask obtained by
// calling the GetProcessAffinityMask function. The affinity of each thread is
// set to this value, but threads are free to subsequently set their affinity,
// as long as it is a subset of the specified affinity mask. Processes cannot
// set their own affinity mask.
//
// A process affinity mask is a bit vector in which each bit represents the
// processors that a process is allowed to run on. A system affinity mask is a
// bit vector in which each bit represents the processors that are configured
// into a system.
//
// A process affinity mask is a subset of the system affinity mask. A process
// is only allowed to run on the processors configured into a system.
// Therefore, the process affinity mask cannot specify a 1 bit for a processor
// when the system affinity mask specifies a 0 bit for that processor.
//
// If the job is nested, the specified processor affinity must be a subset of
// the effective affinity of the parent job. If the specified affinity a
// superset of the affinity of the parent job, it is ignored and the affinity
// of the parent job is used.
//
// This limit must be combined with LimitSubsetAffinity.
func WithAffinity(x uintptr) Limit {
return LimitAffinity.WithValue(x)
}
// WithJobMemoryLimit causes all processes associated with the job to limit the
// job-wide sum of their committed memory. When a process attempts to commit
// memory that would exceed the job-wide limit, it fails.
//
// The value specifies the limit for the virtual memory that can be committed
// for the job object in bytes.
//
// If the job object is associated with a completion port, a
// JOB_OBJECT_MSG_JOB_MEMORY_LIMIT message is sent to the completion port.
func WithJobMemoryLimit(x uintptr) Limit {
return LimitJobMemory.WithValue(x)
}
// WithJobTimeLimit establishes a user-mode execution time limit for the job.
//
// The system adds the current time of the processes associated with the job to
// this limit. For example, if you set this limit to 1 minute, and the job has
// a process that has accumulated 5 minutes of user-mode time, the limit
// actually enforced is 6 minutes.
//
// The system periodically checks to determine whether the sum of the user-mode
// execution time for all processes is greater than this end-of-job limit.
// By default, all processes are terminated and the status code is set to
// ERROR_NOT_ENOUGH_QUOTA.
func WithJobTimeLimit(x time.Duration) Limit {
return LimitJobTime.WithValue(x)
}
// WithProcessMemoryLimit causes all processes associated with the job to limit
// their committed memory. When a process attempts to commit memory that would
// exceed the per-process limit, it fails.
//
// If the job object is associated with a completion port, a
// JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT message is sent to the completion port.
//
// If the job is nested, the effective memory limit is the most restrictive
// memory limit in the job chain.
func WithProcessMemoryLimit(x uintptr) Limit {
return LimitProcessMemory.WithValue(x)
}
// WithProcessTimeLimit establishes a user-mode execution time limit for each
// currently active process and for all future processes associated with the
// job.
//
// The system periodically checks to determine whether each process associated
// with the job has accumulated more user-mode time than the set limit. If it
// has, the process is terminated.
//
// If the job is nested, the effective limit is the most restrictive limit in
// the job chain.
func WithProcessTimeLimit(x time.Duration) Limit {
return LimitProcessTime.WithValue(x)
}
// WithActiveProcessLimit establishes a maximum number of simultaneously active
// processes associated with the job. The ActiveProcessLimit member contains
// additional information.
//
// If you try to associate a process with a job, and this causes the active
// process count to exceed this limit, the process is terminated and the
// association fails.
func WithActiveProcessLimit(x uint32) Limit {
return LimitActiveProcess.WithValue(x)
}
// WithWorkingSetLimit causes all processes associated with the job to use the
// same minimum and maximum working set sizes (specified in bytes).
//
// If maximum working set size is nonzero, minimum working set cannot be zero,
// and vice-versa. The actual limit values can be retrieved with
// MinWorkingSetSize() and MaxWorkingSetSize() methods of LimitWorkingSet.
//
// If the job is nested, the effective working set size is the smallest
// working set size in the job chain.
//
// Note: processes can still empty their working sets using
// SetProcessWorkingSetSize, even when is used. However, you cannot use
// SetProcessWorkingSetSize change the minimum or maximum working set size
// of a process in a job object.
func WithWorkingSetLimit(min, max uintptr) Limit {
return LimitWorkingSet.WithValue(min, max)
}
// WithPriorityClassLimit causes all processes associated with the job to use
// the same priority class.
//
// If the job is nested, the effective priority class is the lowest priority
// class in the job chain.
//
// Processes and threads cannot modify their priority class. The calling
// process must enable the SE_INC_BASE_PRIORITY_NAME privilege.
func WithPriorityClassLimit(x jobapi.PriorityClass) Limit {
return LimitPriorityClass.WithValue(x)
}
// WithSchedulingClassLimit causes all processes in the job to use the same
// scheduling class.
//
// If the job is nested, the effective scheduling class is the lowest
// scheduling class in the job chain.
//
// The valid values are 0 to 9. Use 0 for the least favorable scheduling class
// relative to other threads, and 9 for the most favorable scheduling class
// relative to other threads. By default, this value is 5. To use a scheduling
// class greater than 5, the calling process must enable the
// SE_INC_BASE_PRIORITY_NAME privilege.
func WithSchedulingClassLimit(x uint32) Limit {
return LimitSchedulingClass.WithValue(x)
}
var (
LimitBreakawayOK = basicLimit(jobapi.JOB_OBJECT_LIMIT_BREAKAWAY_OK)
LimitDieOnUnhandledException = basicLimit(jobapi.JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION)
LimitKillOnJobClose = basicLimit(jobapi.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE)
LimitPreserveJobTime = basicLimit(jobapi.JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME)
LimitSubsetAffinity = basicLimit(jobapi.JOB_OBJECT_LIMIT_SUBSET_AFFINITY)
LimitSilentBreakawayOK = basicLimit(jobapi.JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)
LimitAffinity = affinityLimit{basicLimit: basicLimit(jobapi.JOB_OBJECT_LIMIT_AFFINITY)}
LimitJobMemory = jobMemoryLimit{basicLimit: basicLimit(jobapi.JOB_OBJECT_LIMIT_JOB_MEMORY)}
LimitJobTime = jobTimeLimit{basicLimit: basicLimit(jobapi.JOB_OBJECT_LIMIT_JOB_TIME)}
LimitProcessMemory = processMemoryLimit{basicLimit: basicLimit(jobapi.JOB_OBJECT_LIMIT_PROCESS_MEMORY)}
LimitProcessTime = processTimeLimit{basicLimit: basicLimit(jobapi.JOB_OBJECT_LIMIT_PROCESS_TIME)}
LimitActiveProcess = activeProcessLimit{basicLimit: basicLimit(jobapi.JOB_OBJECT_LIMIT_ACTIVE_PROCESS)}
LimitWorkingSet = workingSetLimit{basicLimit: basicLimit(jobapi.JOB_OBJECT_LIMIT_WORKINGSET)}
LimitPriorityClass = priorityClassLimit{basicLimit: basicLimit(jobapi.JOB_OBJECT_LIMIT_PRIORITY_CLASS)}
LimitSchedulingClass = schedulingClassLimit{basicLimit: basicLimit(jobapi.JOB_OBJECT_LIMIT_SCHEDULING_CLASS)}
)
type basicLimit jobapi.LimitFlag
func (l basicLimit) set(job *JobObject) {
job.ExtendedLimits.BasicLimitInformation.LimitFlags |= uint32(l)
}
func (l basicLimit) reset(job *JobObject) {
job.ExtendedLimits.BasicLimitInformation.LimitFlags &^= uint32(l)
}
func (l basicLimit) IsSet(job *JobObject) bool {
return job.ExtendedLimits.BasicLimitInformation.LimitFlags&uint32(l) > 0
}
func (l basicLimit) Value(job *JobObject) any {
return l.IsSet(job)
}
type affinityLimit struct {
basicLimit
affinity uintptr
}
func (l affinityLimit) WithValue(x uintptr) affinityLimit {
l.affinity = x
return l
}
func (l affinityLimit) LimitValue(job *JobObject) uintptr {
return job.ExtendedLimits.BasicLimitInformation.Affinity
}
func (l affinityLimit) set(job *JobObject) {
job.ExtendedLimits.BasicLimitInformation.Affinity = l.affinity
l.basicLimit.set(job)
}
func (l affinityLimit) Value(job *JobObject) any {
return l.LimitValue(job)
}
type jobMemoryLimit struct {
basicLimit
jobMemory uintptr
}
func (l jobMemoryLimit) WithValue(x uintptr) jobMemoryLimit {
l.jobMemory = x
return l
}
func (l jobMemoryLimit) LimitValue(job *JobObject) uintptr {
return job.ExtendedLimits.JobMemoryLimit
}
func (l jobMemoryLimit) set(job *JobObject) {
job.ExtendedLimits.JobMemoryLimit = l.jobMemory
l.basicLimit.set(job)
}
func (l jobMemoryLimit) Value(job *JobObject) any {
return l.LimitValue(job)
}
type jobTimeLimit struct {
basicLimit
jobTime int64
}
// Time limits and counters are specified in 100-nanosecond ticks.
const timeFraction = 100
func (l jobTimeLimit) WithValue(x time.Duration) jobTimeLimit {
l.jobTime = x.Nanoseconds() / timeFraction
return l
}
func (l jobTimeLimit) LimitValue(job *JobObject) time.Duration {
return time.Duration(job.ExtendedLimits.BasicLimitInformation.PerJobUserTimeLimit * timeFraction)
}
func (l jobTimeLimit) set(job *JobObject) {
job.ExtendedLimits.BasicLimitInformation.PerJobUserTimeLimit = l.jobTime
l.basicLimit.set(job)
}
func (l jobTimeLimit) Value(job *JobObject) any {
return l.LimitValue(job)
}
type processMemoryLimit struct {
basicLimit
processMemory uintptr
}
func (l processMemoryLimit) WithValue(x uintptr) processMemoryLimit {
l.processMemory = x
return l
}
func (l processMemoryLimit) LimitValue(job *JobObject) uintptr {
return job.ExtendedLimits.ProcessMemoryLimit
}
func (l processMemoryLimit) set(job *JobObject) {
job.ExtendedLimits.ProcessMemoryLimit = l.processMemory
l.basicLimit.set(job)
}
func (l processMemoryLimit) Value(job *JobObject) any {
return l.LimitValue(job)
}
type processTimeLimit struct {
basicLimit
processTime int64
}
func (l processTimeLimit) WithValue(x time.Duration) processTimeLimit {
l.processTime = x.Nanoseconds() / timeFraction
return l
}
func (l processTimeLimit) LimitValue(job *JobObject) time.Duration {
return time.Duration(job.ExtendedLimits.BasicLimitInformation.PerProcessUserTimeLimit * timeFraction)
}
func (l processTimeLimit) set(job *JobObject) {
job.ExtendedLimits.BasicLimitInformation.PerProcessUserTimeLimit = l.processTime
l.basicLimit.set(job)
}
func (l processTimeLimit) Value(job *JobObject) any {
return l.LimitValue(job)
}
type activeProcessLimit struct {
basicLimit
procs uint32
}
func (l activeProcessLimit) WithValue(x uint32) activeProcessLimit {
l.procs = x
return l
}
func (l activeProcessLimit) LimitValue(job *JobObject) uint32 {
return job.ExtendedLimits.BasicLimitInformation.ActiveProcessLimit
}
func (l activeProcessLimit) set(job *JobObject) {
job.ExtendedLimits.BasicLimitInformation.ActiveProcessLimit = uint32(l.procs)
l.basicLimit.set(job)
}
func (l activeProcessLimit) Value(job *JobObject) any {
return l.LimitValue(job)
}
type workingSetLimit struct {
basicLimit
wsMin uintptr
wsMax uintptr
}
func (l workingSetLimit) WithValue(min, max uintptr) workingSetLimit {
l.wsMin = min
l.wsMax = max
return l
}
func (l workingSetLimit) MinWorkingSetSize(job *JobObject) uintptr {
return job.ExtendedLimits.BasicLimitInformation.MinimumWorkingSetSize
}
func (l workingSetLimit) MaxWorkingSetSize(job *JobObject) uintptr {
return job.ExtendedLimits.BasicLimitInformation.MaximumWorkingSetSize
}
func (l workingSetLimit) set(job *JobObject) {
job.ExtendedLimits.BasicLimitInformation.MinimumWorkingSetSize = l.wsMin
job.ExtendedLimits.BasicLimitInformation.MaximumWorkingSetSize = l.wsMax
l.basicLimit.set(job)
}
type priorityClassLimit struct {
basicLimit
prio jobapi.PriorityClass
}
func (l priorityClassLimit) WithValue(x jobapi.PriorityClass) priorityClassLimit {
l.prio = x
return l
}
func (l priorityClassLimit) LimitValue(job *JobObject) jobapi.PriorityClass {
return jobapi.PriorityClass(job.ExtendedLimits.BasicLimitInformation.PriorityClass)
}
func (l priorityClassLimit) set(job *JobObject) {
job.ExtendedLimits.BasicLimitInformation.PriorityClass = uint32(l.prio)
l.basicLimit.set(job)
}
func (l priorityClassLimit) Value(job *JobObject) any {
return l.LimitValue(job)
}
type schedulingClassLimit struct {
basicLimit
schedClass uint32
}
func (l schedulingClassLimit) WithValue(x uint32) schedulingClassLimit {
l.schedClass = x
return l
}
func (l schedulingClassLimit) LimitValue(job *JobObject) uint32 {
return job.ExtendedLimits.BasicLimitInformation.SchedulingClass
}
func (l schedulingClassLimit) set(job *JobObject) {
job.ExtendedLimits.BasicLimitInformation.SchedulingClass = l.schedClass
l.basicLimit.set(job)
}
func (l schedulingClassLimit) Value(job *JobObject) any {
return l.LimitValue(job)
}