]> Cypherpunks.ru repositories - goredo.git/blob - js.go
Repetitive OOD optimization
[goredo.git] / js.go
1 /*
2 goredo -- djb's redo implementation on pure Go
3 Copyright (C) 2020-2021 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 // Jobserver
19
20 package main
21
22 import (
23         "flag"
24         "fmt"
25         "log"
26         "os"
27         "os/signal"
28         "strconv"
29         "strings"
30         "sync"
31         "syscall"
32 )
33
34 const (
35         EnvJobs = "REDO_JOBS"
36         EnvJSFd = "REDO_JS_FD"
37 )
38
39 var (
40         JSR       *os.File
41         JSW       *os.File
42         jsTokens  int
43         jsTokensM sync.Mutex
44
45         flagJobs = flag.Int("j", -1, fmt.Sprintf("number of parallel jobs (0=inf, <0=1) (%s)", EnvJobs))
46 )
47
48 func jsInit() {
49         jsRaw := os.Getenv(EnvJSFd)
50         if jsRaw == "NO" {
51                 // infinite jobs
52                 return
53         }
54         if jsRaw != "" {
55                 cols := strings.Split(jsRaw, ",")
56                 if len(cols) != 2 {
57                         log.Fatalln("invalid", EnvJSFd, "format")
58                 }
59                 JSR = mustParseFd(cols[0], "JSR")
60                 JSW = mustParseFd(cols[1], "JSW")
61                 jsRelease("ifchange entered")
62
63                 killed := make(chan os.Signal, 0)
64                 signal.Notify(killed, syscall.SIGTERM, syscall.SIGINT)
65                 go func() {
66                         <-killed
67                         jsTokensM.Lock()
68                         for ; jsTokens > 0; jsTokens-- {
69                                 jsReleaseNoLock()
70                         }
71                         os.Exit(1)
72                 }()
73                 return
74         }
75
76         jobs := uint64(1)
77         var err error
78         if *flagJobs == 0 {
79                 jobs = 0
80         } else if *flagJobs > 0 {
81                 jobs = uint64(*flagJobs)
82         } else if v := os.Getenv(EnvJobs); v != "" {
83                 jobs, err = strconv.ParseUint(v, 10, 64)
84                 if err != nil {
85                         log.Fatalln("can not parse", EnvJobs, err)
86                 }
87         }
88         if jobs == 0 {
89                 // infinite jobs
90                 return
91         }
92
93         JSR, JSW, err = os.Pipe()
94         if err != nil {
95                 log.Fatalln(err)
96         }
97         for i := uint64(0); i < jobs; i++ {
98                 jsRelease("initial fill")
99         }
100 }
101
102 func jsReleaseNoLock() {
103         if n, err := JSW.Write([]byte{0}); err != nil || n != 1 {
104                 log.Fatalln("can not write JSW:", err)
105         }
106 }
107
108 func jsRelease(ctx string) int {
109         if JSW == nil {
110                 return 0
111         }
112         trace(CJS, "release from %s", ctx)
113         jsTokensM.Lock()
114         jsTokens--
115         left := jsTokens
116         jsReleaseNoLock()
117         jsTokensM.Unlock()
118         return left
119 }
120
121 func jsAcquire(ctx string) {
122         if JSR == nil {
123                 return
124         }
125         trace(CJS, "acquire for %s", ctx)
126         if n, err := JSR.Read([]byte{0}); err != nil || n != 1 {
127                 log.Fatalln("can not read JSR:", err)
128         }
129         jsTokensM.Lock()
130         jsTokens++
131         jsTokensM.Unlock()
132         trace(CJS, "acquired for %s", ctx)
133 }