@amritk/nish-aarch64-darwin 0.34.0 → 0.35.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.
@@ -52,12 +52,24 @@
52
52
  * answer -95, as `setIdlePriority` does on Darwin, and on wasi creating or
53
53
  * opening a region answers -95 too.
54
54
  *
55
- * Results are 0 or a count on success and a negated errno on failure. Nothing
56
- * here allocates: the table is a fixed array, and a mapping is the kernel's. */
55
+ * **A window** (`nishshm_lend`) is a `u8[]` whose data is a range of the
56
+ * mapping, so a program writes the region with `copyBytes` and index stores
57
+ * and no copy. Its header is a record of this file's, malloc'd (never the
58
+ * arena: a `region()` would free it under the program) and never freed: the
59
+ * program may keep the array past `nishshm_give_back` and `nishshm_close`,
60
+ * and both leave it a header of length 0 and no data, so an index after them
61
+ * is a bounds panic, not a read of an unmapped page. A loop lends again with
62
+ * the window it gave back as `reuse`, which re-points that header and takes
63
+ * no memory.
64
+ *
65
+ * Results are 0 or a count on success and a negated errno on failure. The
66
+ * table is a fixed array, a mapping is the kernel's, and a window's header is
67
+ * the one allocation. */
57
68
 
58
69
  #define _GNU_SOURCE /* `syscall`, for the futex */
59
70
  #include <errno.h>
60
71
  #include <stdint.h>
72
+ #include <stdlib.h>
61
73
  #include <string.h>
62
74
 
63
75
  #include "nish.h"
@@ -90,10 +102,20 @@
90
102
  /* The longest name. Darwin's shm_open takes 31 bytes with its leading '/'. */
91
103
  #define NISHSHM_NAME_MAX 30
92
104
 
105
+ /* A window `lend` made: a `u8[]` header whose data is the mapping. The header
106
+ comes first, so the program's array pointer is the record's. */
107
+ typedef struct nishshm_window {
108
+ nish_array hdr;
109
+ uint8_t *lent; /* `hdr.data` as lent; NULL once given back */
110
+ uint64_t lent_len; /* the length lent */
111
+ struct nishshm_window *next; /* the region's next window */
112
+ } nishshm_window;
113
+
93
114
  typedef struct nishshm_region {
94
115
  uint8_t *base; /* the mapping, NULL while the slot is free */
95
116
  uint64_t size; /* its length in bytes */
96
117
  int32_t gen; /* the high bits of the slot's handle: 0 never used, 32767 retired */
118
+ nishshm_window *windows; /* every window this mapping lent, given back or not */
97
119
  } nishshm_region;
98
120
 
99
121
  /* NULL until this thread first maps a region. Slot 0 is never used, so no
@@ -312,6 +334,65 @@ void nishshm_write(int32_t h, int32_t at, const uint8_t *src, uint64_t n, uint64
312
334
  memcpy(dst, src + off, len);
313
335
  }
314
336
 
337
+ /* -- windows ----------------------------------------------------------------- */
338
+
339
+ /* The record of `a` among the region's windows, or NULL. A pointer walk, so a
340
+ header no window has is never read as one. */
341
+ static nishshm_window *window_of(nishshm_region *r, const nish_array *a) {
342
+ nishshm_window *w = r->windows;
343
+ while (w != NULL && &w->hdr != a) w = w->next;
344
+ return w;
345
+ }
346
+
347
+ /* A `u8[]` of `len` bytes whose data is the region's bytes at `at`, checked as
348
+ a byte copy's window is. `reuse` NULL takes a new header, which is malloc'd
349
+ and never freed: the program may hold it after any giveBack or close, so it
350
+ must stay a header, one that reads as empty. Otherwise `reuse` must be a
351
+ window this region lent and was given back, and is re-pointed. */
352
+ nish_array *nishshm_lend(int32_t h, int32_t at, int32_t len, nish_array *reuse) {
353
+ nishshm_region *r = region_checked(h);
354
+ uint8_t *p = window(h, at, (uint64_t)(int64_t)len, 0, (uint64_t)(int64_t)len);
355
+ nishshm_window *w;
356
+ if (reuse != NULL) {
357
+ w = window_of(r, reuse);
358
+ if (__builtin_expect(w == NULL || w->lent != NULL, 0))
359
+ shm_fail("reuse of length ", (int64_t)reuse->len,
360
+ " is not a window this region lent and was given back", 0, NULL);
361
+ } else {
362
+ w = (nishshm_window *)malloc(sizeof *w);
363
+ if (__builtin_expect(w == NULL, 0))
364
+ shm_fail("lend of ", len, " bytes found no memory for the window's header", 0, NULL);
365
+ w->next = r->windows;
366
+ r->windows = w;
367
+ }
368
+ w->hdr.len = w->hdr.cap = (uint64_t)len;
369
+ w->hdr.data = (char *)p;
370
+ w->lent = p;
371
+ w->lent_len = (uint64_t)len;
372
+ return &w->hdr;
373
+ }
374
+
375
+ /* Empties a lent window and answers its length. A pop or a shorter `length`
376
+ keeps the window; a push that moved its data took it out of the region, and
377
+ that, a second giveBack, or another region's window, panics. */
378
+ int32_t nishshm_give_back(int32_t h, nish_array *a) {
379
+ nishshm_region *r = region_checked(h);
380
+ nishshm_window *w = window_of(r, a);
381
+ if (__builtin_expect(w == NULL || w->lent == NULL, 0))
382
+ shm_fail("window of length ", (int64_t)a->len,
383
+ " is not lent by this region: it was given back, or another region lent it", 0,
384
+ NULL);
385
+ if (__builtin_expect((uint8_t *)a->data != w->lent || a->len > w->lent_len, 0))
386
+ shm_fail("window of length ", (int64_t)a->len,
387
+ " is no longer the region's bytes: a push moved it, so it cannot be given back", 0,
388
+ NULL);
389
+ int32_t n = (int32_t)a->len;
390
+ a->len = a->cap = 0;
391
+ a->data = NULL;
392
+ w->lent = NULL;
393
+ return n;
394
+ }
395
+
315
396
  /* -- regions ----------------------------------------------------------------- */
316
397
 
317
398
  int32_t nishshm_size(int32_t h) { return (int32_t)region_checked(h)->size; }
@@ -486,6 +567,16 @@ int32_t nishshm_unlink(const char *name) {
486
567
  int32_t nishshm_close(int32_t h) {
487
568
  nishshm_region *r = region_of(h);
488
569
  if (r == NULL) return -9;
570
+ /* Every window still on the mapping reads as empty before the pages go: one
571
+ a push moved off it is the program's array now, and is left alone. */
572
+ for (nishshm_window *w = r->windows; w != NULL; w = w->next) {
573
+ if (w->lent != NULL && (uint8_t *)w->hdr.data == w->lent) {
574
+ w->hdr.len = w->hdr.cap = 0;
575
+ w->hdr.data = NULL;
576
+ }
577
+ w->lent = NULL;
578
+ }
579
+ r->windows = NULL;
489
580
  munmap(r->base, (size_t)r->size);
490
581
  r->base = NULL;
491
582
  r->size = 0;