forked from Codehardt/go-priority
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpriority_linux.go
76 lines (69 loc) · 2.24 KB
/
priority_linux.go
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
package priority
import (
"errors"
"os"
"strconv"
"syscall"
)
// priority in unix usually is a range between -19/-20 (high prio) and
// +19/+20 (low prio). 0 equals the default priority.
var priorityMapping = map[Priority]int{
PriorityVeryLow: 19,
PriorityLow: 10,
PriorityMedium: 0,
PriorityHigh: -10,
PriorityVeryHigh: -20,
}
func setPriority(priority Priority) error {
// On Linux, setpriority only affects the calling thread, not the whole process.
// To work around this, we list all threads in the process and set the priority for each of them.
// However, this is unfortunately racy as new threads can be created at any time.
const maxThreadListings = 5
for i := 0; i < maxThreadListings; i++ {
var threadWithWrongPrioFound bool
threads, err := os.ReadDir("/proc/self/task")
if err != nil {
return err
}
for _, thread := range threads {
threadId, err := strconv.Atoi(thread.Name())
if err != nil { // Should never happen since the task directory only contains the thread IDs
return err
}
currentPriority, err := getThreadPriority(threadId)
if err != nil {
if err == syscall.EINVAL {
// Bad thread ID - possibly a race where the thread terminated between the read and the getpriority
continue
}
return err
}
if currentPriority != priorityMapping[priority] {
threadWithWrongPrioFound = true
if err := syscall.Setpriority(syscall.PRIO_PROCESS, threadId, priorityMapping[priority]); err != nil {
if err == syscall.EINVAL {
continue
}
return err
}
}
}
if !threadWithWrongPrioFound {
// All threads already had the new priority when we checked them
// Any threads they possibly spawned after the thread listing therefore also have inherited
// the correct priority
return nil
}
}
// During each iteration before, we found new threads.
// We give up at this point.
return errors.New("process too volatile, could not set priority for all threads")
}
func getThreadPriority(tid int) (int, error) {
kernelPrio, err := syscall.Getpriority(syscall.PRIO_PROCESS, tid)
if err != nil {
return 0, err
}
// getpriority returns a 0-39 range, where 39 is equivalent to priority -20 and 0 is equivalent to priority 19
return 20 - kernelPrio, nil
}