X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=js.go;h=701d26d39683891c0a01762758f3ce63358f1cea;hb=314f58ec690c7321535d6718e8d3a0ecb4cac019;hp=ab1190e00c00759f48899030271986704d3c9ae4;hpb=f15fe27971bcf37a06bb9542ea1907f11444515a;p=goredo.git diff --git a/js.go b/js.go index ab1190e..701d26d 100644 --- a/js.go +++ b/js.go @@ -1,6 +1,6 @@ /* -goredo -- redo implementation on pure Go -Copyright (C) 2020 Sergey Matveev +goredo -- djb's redo implementation on pure Go +Copyright (C) 2020-2021 Sergey Matveev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,59 +19,115 @@ along with this program. If not, see . package main -import "os" +import ( + "flag" + "fmt" + "log" + "os" + "os/signal" + "strconv" + "strings" + "sync" + "syscall" +) + +const ( + EnvJobs = "REDO_JOBS" + EnvJSFd = "REDO_JS_FD" +) var ( - JSR *os.File - JSW *os.File + JSR *os.File + JSW *os.File + jsTokens int + jsTokensM sync.Mutex + + flagJobs = flag.Int("j", -1, fmt.Sprintf("number of parallel jobs (0=inf, <0=1) (%s)", EnvJobs)) ) func jsInit() { - jsrRaw := os.Getenv(RedoJSRFdEnv) - jswRaw := os.Getenv(RedoJSWFdEnv) - if (jsrRaw == "" && jswRaw != "") || (jsrRaw != "" && jswRaw == "") { - panic("both JSR and JSW must be set") - } - if jsrRaw == "NO" { + jsRaw := os.Getenv(EnvJSFd) + if jsRaw == "NO" { // infinite jobs return } - if jsrRaw != "" { - JSR = mustParseFd(jsrRaw, "JSR") - JSW = mustParseFd(jswRaw, "JSW") - jsRelease() + if jsRaw != "" { + cols := strings.Split(jsRaw, ",") + if len(cols) != 2 { + log.Fatalln("invalid", EnvJSFd, "format") + } + JSR = mustParseFd(cols[0], "JSR") + JSW = mustParseFd(cols[1], "JSW") + jsRelease("ifchange entered") + + killed := make(chan os.Signal, 0) + signal.Notify(killed, syscall.SIGTERM, syscall.SIGINT) + go func() { + <-killed + jsTokensM.Lock() + for ; jsTokens > 0; jsTokens-- { + jsReleaseNoLock() + } + os.Exit(1) + }() return } - if *JobsN == 0 { + + jobs := uint64(1) + var err error + if *flagJobs == 0 { + jobs = 0 + } else if *flagJobs > 0 { + jobs = uint64(*flagJobs) + } else if v := os.Getenv(EnvJobs); v != "" { + jobs, err = strconv.ParseUint(v, 10, 64) + if err != nil { + log.Fatalln("can not parse", EnvJobs, err) + } + } + if jobs == 0 { // infinite jobs return } - var err error + JSR, JSW, err = os.Pipe() if err != nil { - panic(err) + log.Fatalln(err) } - for i := uint(0); i < *JobsN; i++ { - jsRelease() + for i := uint64(0); i < jobs; i++ { + jsRelease("initial fill") } } -func jsRelease() { - if JSW == nil { - return - } - trace(CJS, "release") +func jsReleaseNoLock() { if n, err := JSW.Write([]byte{0}); err != nil || n != 1 { - panic("can not write JSW") + log.Fatalln("can not write JSW:", err) + } +} + +func jsRelease(ctx string) int { + if JSW == nil { + return 0 } + trace(CJS, "release from %s", ctx) + jsTokensM.Lock() + jsTokens-- + left := jsTokens + jsReleaseNoLock() + jsTokensM.Unlock() + return left } -func jsAcquire() { +func jsAcquire(ctx string) { if JSR == nil { return } - trace(CJS, "acquire") + trace(CJS, "acquire for %s", ctx) if n, err := JSR.Read([]byte{0}); err != nil || n != 1 { - panic("can not read JSR") + log.Fatalln("can not read JSR:", err) } + jsTokensM.Lock() + jsTokens++ + jsTokensM.Unlock() + trace(CJS, "acquired for %s", ctx) }