@amritk/nish-x86_64-linux 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -84,6 +84,11 @@ export const PREFORK_STOPPED: i32 = -1
84
84
  * supervisor could not listen for SIGTERM and so starts none.
85
85
  */
86
86
  export const PREFORK_SPAWN_FAILED: i32 = -2
87
+ /**
88
+ * What `preforkWith` answers in the supervisor when `restart` is off and every
89
+ * worker has exited.
90
+ */
91
+ export const PREFORK_WORKERS_EXITED: i32 = -3
87
92
 
88
93
  /** The supervisor's numbers; every one is checked by `preforkWith`. */
89
94
  export class PreforkConfig {
@@ -99,6 +104,11 @@ export class PreforkConfig {
99
104
  quickExitMs: i32 = 1000
100
105
  /** How long the workers get to exit after SIGTERM before SIGKILL. */
101
106
  graceMs: i32 = 5000
107
+ /**
108
+ * Start a worker that exited again. Off, a worker that exits stays gone,
109
+ * and the supervisor returns once none is left.
110
+ */
111
+ restart: boolean = true
102
112
  }
103
113
 
104
114
  /** True when `s` is one or more ASCII digits and nothing else. */
@@ -177,6 +187,8 @@ class PreforkSlot {
177
187
  pid: i32 = 0
178
188
  /** The wait before the last restart, 0 after a worker that ran long. */
179
189
  delay: i32 = 0
190
+ /** The worker exited with `restart` off, and is never started again. */
191
+ gone: boolean = false
180
192
  }
181
193
 
182
194
  /** The supervisor's state while it runs. */
@@ -269,7 +281,9 @@ class PreforkSupervisor {
269
281
  const slot: PreforkSlot = this.slots[index]
270
282
  this.running = this.running - 1
271
283
  slot.pid = 0
272
- if (!stopping) {
284
+ if (!this.config.restart) {
285
+ slot.gone = true
286
+ } else if (!stopping) {
273
287
  this.backoff(slot, preforkNowMs(), false)
274
288
  }
275
289
  }
@@ -285,7 +299,7 @@ class PreforkSupervisor {
285
299
  const now: i64 = preforkNowMs()
286
300
  for (let i: i32 = 0; i < toI32(this.slots.length); i++) {
287
301
  const slot: PreforkSlot = this.slots[i]
288
- if (slot.pid === 0 && slot.at <= now && !this.start(i)) {
302
+ if (slot.pid === 0 && !slot.gone && slot.at <= now && !this.start(i)) {
289
303
  if (first) {
290
304
  return false
291
305
  }
@@ -355,7 +369,9 @@ const preforkInvalid = (config: PreforkConfig): string => {
355
369
 
356
370
  /**
357
371
  * In a worker, its index. In the supervisor, run the workers until SIGTERM or
358
- * SIGINT and answer `PREFORK_STOPPED`, or `PREFORK_SPAWN_FAILED` when a worker's
372
+ * SIGINT and answer `PREFORK_STOPPED`; with `restart` off, also until every
373
+ * worker has exited, answering `PREFORK_WORKERS_EXITED`; or
374
+ * `PREFORK_SPAWN_FAILED` when a worker's
359
375
  * first start failed (those already started are stopped first) or no signal
360
376
  * listener could be made (no worker is started). Panics on a config
361
377
  * `preforkInvalid` names a field of.
@@ -399,6 +415,10 @@ export const preforkWith = (args: string[], config: PreforkConfig): i32 => {
399
415
  running = false
400
416
  } else {
401
417
  supervisor.reap(false)
418
+ if (!config.restart && supervisor.running === 0) {
419
+ result = PREFORK_WORKERS_EXITED
420
+ running = false
421
+ }
402
422
  supervisor.restart(false)
403
423
  }
404
424
  }
package/std/random.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * import { Rng } from "nish/random";
6
6
  *
7
7
  * const r = new Rng(42);
8
- * const die: i32 = 1 + (r.nextI32() >>> 1) % 6;
8
+ * const die: i32 = r.nextInt(1, 6); // 1 to 6, each with equal chance
9
9
  * const u: f64 = r.nextF64(); // in [0, 1)
10
10
  *
11
11
  * The state is one 32-bit integer. Each step adds the odd constant
@@ -24,8 +24,11 @@
24
24
  * two's-complement wrap natively and answer `(a + b) | 0` and `Math.imul(a, b)`
25
25
  * under Node (docs/LANGUAGE.md, "nish:unsafe"); every shift has a constant
26
26
  * count, and `^` and `>>> 16` answer the same 32 bits in JavaScript as in the
27
- * compiled program. `nextF64` builds its double from integers below 2^53, so
28
- * its products and sums are exact both ways. The program a test prints under
27
+ * compiled program. `nextInt` reads its span and its draws as unsigned
28
+ * counts with no `u32` (whose conversions saturate under Node): the sign bit
29
+ * flipped orders them under a signed compare, and the remainder is taken in
30
+ * pieces that stay below 2^31. `nextF64` builds its double from integers
31
+ * below 2^53, so its products and sums are exact both ways. The program a test prints under
29
32
  * Node is the one it prints compiled (docs/RUN_UNDER_NODE.md).
30
33
  *
31
34
  * It is not for cryptography: a key or a nonce comes from
@@ -37,7 +40,7 @@
37
40
  * would be a write their caller can see, and is refused as any such write is;
38
41
  * give each task its own, seeded from its index.
39
42
  */
40
- import { wrappingAdd, wrappingMul } from "nish:unsafe"
43
+ import { wrappingAdd, wrappingMul, wrappingSub } from "nish:unsafe"
41
44
 
42
45
  /** 0x9E3779B9 as an `i32`: the Weyl increment, odd, so the walk visits every state. */
43
46
  const GOLDEN: i32 = -1640531527
@@ -54,6 +57,35 @@ const TWO_26: f64 = 67108864.0
54
57
  /** 2^53, which scales a 53-bit integer into [0, 1). */
55
58
  const TWO_53: f64 = 9007199254740992.0
56
59
 
60
+ /** The sign bit: `x ^ SIGN` orders the bits of `x` as an unsigned count under a signed compare. */
61
+ const SIGN: i32 = -2147483648
62
+
63
+ /** 2^31 - 1, the `i32` just below 2^31, from which `remainder` finds 2^31 mod m. */
64
+ const MAX: i32 = 2147483647
65
+
66
+ /** Whether `a < b` when both are read as unsigned 32-bit counts. */
67
+ const below = (a: i32, b: i32): boolean => (a ^ SIGN) < (b ^ SIGN)
68
+
69
+ /**
70
+ * `a mod m` with both read as unsigned 32-bit counts and `m` not 0. A count
71
+ * of 2^31 or more is a negative `i32`, so it is taken apart into pieces a
72
+ * signed `%` answers the same in JavaScript, and every sum stays below 2^31.
73
+ */
74
+ const remainder = (a: i32, m: i32): i32 => {
75
+ if (m < 0) {
76
+ // m is 2^31 or more, so a is less than 2m: at most one m comes off.
77
+ return below(a, m) ? a : wrappingSub(a, m)
78
+ }
79
+ if (a >= 0) {
80
+ return a % m
81
+ }
82
+ // a is 2^31 + low, so a mod m is low plus 2^31 mod m, added mod m.
83
+ const low: i32 = (a ^ SIGN) % m
84
+ const high: i32 = wrappingAdd(MAX % m, 1) % m
85
+ const room: i32 = wrappingSub(m, high)
86
+ return low >= room ? wrappingSub(low, room) : wrappingAdd(low, high)
87
+ }
88
+
57
89
  /** MurmurHash3's `fmix32`: every bit of `h` into every bit of the answer, a bijection on 32 bits. */
58
90
  const mix = (h: i32): i32 => {
59
91
  let x: i32 = h
@@ -91,4 +123,34 @@ export class Rng {
91
123
  const lo: i32 = this.nextI32() >>> 6
92
124
  return (toF64(hi) * TWO_26 + toF64(lo)) / TWO_53
93
125
  }
126
+
127
+ /**
128
+ * An integer in [lo, hi], both ends included, each with equal chance;
129
+ * `nextInt(1, 6)` is a die. It panics when `lo` is greater than `hi`, and
130
+ * the whole `i32` range, `nextInt(-2147483648, 2147483647)`, is one
131
+ * `nextI32()`.
132
+ *
133
+ * There is no modulo bias: where the span `hi - lo + 1`, an unsigned count
134
+ * up to 2^32, does not divide 2^32 evenly, a draw among the lowest
135
+ * 2^32 mod span is refused and drawn again, and what is left holds every
136
+ * answer equally often. Fewer than half the draws are ever refused, so an
137
+ * answer takes one `nextI32()` step usually and fewer than two on average,
138
+ * and a sequence is still the seed's.
139
+ */
140
+ nextInt(lo: i32, hi: i32): i32 {
141
+ if (lo > hi) {
142
+ panic("Rng.nextInt: lo is greater than hi")
143
+ }
144
+ const span: i32 = wrappingAdd(wrappingSub(hi, lo), 1)
145
+ if (span === 0) {
146
+ return this.nextI32()
147
+ }
148
+ // 2^32 mod span, as (2^32 - span) mod span.
149
+ const refused: i32 = remainder(wrappingSub(0, span), span)
150
+ let draw: i32 = this.nextI32()
151
+ while (below(draw, refused)) {
152
+ draw = this.nextI32()
153
+ }
154
+ return wrappingAdd(lo, remainder(draw, span))
155
+ }
94
156
  }