X-Git-Url: http://www.git.cypherpunks.ru/?p=goredo.git;a=blobdiff_plain;f=js.go;h=701d26d39683891c0a01762758f3ce63358f1cea;hp=d3ed7bb3fb752b5b7566c1251db7ae11b3c93a1f;hb=ce96a1c785b32af13264225c0bf7ae8370a5af21;hpb=bc7701e7a4f95cee680e0736ec3e68a8b0b5c09f diff --git a/js.go b/js.go index d3ed7bb..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,51 +19,103 @@ 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") + 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++ { + for i := uint64(0); i < jobs; i++ { jsRelease("initial fill") } } -func jsRelease(ctx string) { +func jsReleaseNoLock() { + if n, err := JSW.Write([]byte{0}); err != nil || n != 1 { + log.Fatalln("can not write JSW:", err) + } +} + +func jsRelease(ctx string) int { if JSW == nil { - return + return 0 } trace(CJS, "release from %s", ctx) - if n, err := JSW.Write([]byte{0}); err != nil || n != 1 { - panic("can not write JSW") - } + jsTokensM.Lock() + jsTokens-- + left := jsTokens + jsReleaseNoLock() + jsTokensM.Unlock() + return left } func jsAcquire(ctx string) { @@ -72,7 +124,10 @@ func jsAcquire(ctx string) { } 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) }