Skip to content

Commit 3a8e6bf

Browse files
committed
all: initial implementation
1 parent 9d2897f commit 3a8e6bf

File tree

6 files changed

+113
-0
lines changed

6 files changed

+113
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
# mkill
2+
23
mkill limites the number of threads in a Go program

example/main.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package main
2+
3+
import (
4+
"time"
5+
6+
"github.com/changkun/mkill"
7+
)
8+
9+
func main() {
10+
mkill.GOMAXTHREADS(10)
11+
for {
12+
time.Sleep(time.Second)
13+
go func() {
14+
time.Sleep(time.Second * 10)
15+
}()
16+
}
17+
}

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/changkun/mkill
2+
3+
go 1.13

mkill.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package mkill
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"os/exec"
7+
"runtime"
8+
"strconv"
9+
"strings"
10+
"sync/atomic"
11+
"time"
12+
)
13+
14+
var (
15+
pid = os.Getpid()
16+
maxThread = int32(runtime.NumCPU())
17+
interval = time.Second
18+
debug = true
19+
)
20+
21+
func checkwork() {
22+
_, err := getThreads()
23+
if err != nil {
24+
panic(fmt.Sprintf("mkill: failed to use the library: %v", err))
25+
}
26+
}
27+
28+
func init() {
29+
checkwork()
30+
31+
if debug {
32+
fmt.Printf("mkill: pid %v, maxThread %v, interval %v\n", pid, maxThread, interval)
33+
}
34+
go func() {
35+
t := time.NewTicker(interval)
36+
for {
37+
select {
38+
case <-t.C:
39+
n, _ := getThreads()
40+
nkill := int32(n) - atomic.LoadInt32(&maxThread)
41+
if nkill <= 0 {
42+
if debug {
43+
fmt.Printf("mkill: checked #threads total %v / max %v\n", n, maxThread)
44+
}
45+
continue
46+
}
47+
for i := int32(0); i < nkill; i++ {
48+
go func() {
49+
runtime.LockOSThread()
50+
}()
51+
}
52+
if debug {
53+
fmt.Printf("mkill: killing #threads, remaining: %v\n", n)
54+
}
55+
}
56+
}
57+
}()
58+
}
59+
60+
// GOMAXTHREADS change the limites of the maximum threads in runtime
61+
// and returns the previous number of threads limit
62+
func GOMAXTHREADS(n int) int {
63+
return int(atomic.SwapInt32(&maxThread, int32(n)))
64+
}
65+
66+
// getThreads returns the number of running threads
67+
// Linux:
68+
func getThreads() (int, error) {
69+
out, err := exec.Command("bash", "-c", cmdThreads).Output()
70+
if err != nil {
71+
return 0, fmt.Errorf("mkill: failed to fetch #threads: %v", err)
72+
}
73+
n, err := strconv.Atoi(strings.TrimSpace(string(out)))
74+
if err != nil {
75+
return 0, fmt.Errorf("mkill: failed to parse #threads: %v", err)
76+
}
77+
return n, nil
78+
}

platform_darwin.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// +build darwin
2+
3+
package mkill
4+
5+
import "fmt"
6+
7+
var cmdThreads = fmt.Sprintf("ps M %d | wc -l", pid)

platform_linux.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// +build linux
2+
3+
package mkill
4+
5+
import "fmt"
6+
7+
var cmdThreads = fmt.Sprintf("ps hH p %d | wc -l", pid)

0 commit comments

Comments
 (0)