My Project
vspace.h
Go to the documentation of this file.
1 #ifndef VSPACE_H
2 #define VSPACE_H
3 #include <fcntl.h>
4 #include <stddef.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/mman.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11 #include <assert.h>
12 #include <new> // for placement new
13 #include "kernel/mod2.h"
14 
15 #ifdef HAVE_VSPACE
16 
17 #if __cplusplus >= 201100
18 #define HAVE_CPP_THREADS
19 #include <atomic>
20 #else
21 #undef HAVE_CPP_THREADS
22 #endif
23 
24 // vspace is a C++ library designed to allow processes in a
25 // multi-process environment to interoperate via mmapped shared memory.
26 // The library provides facilities for shared memory allocation and
27 // deallocation, shared mutexes, semaphores, queues, lists, and hash
28 // tables.
29 //
30 // The underlying file is organized starting with a block containing
31 // meta information such as free lists and process information necessary
32 // for IPC, followed by one or more segments of mmapped memory. Each
33 // address within the file is represented via its offset from the
34 // beginning of the first segment.
35 //
36 // These offsets are wrapped within the VRef<T> class, which works like
37 // a T* pointer, but transparently maps file offsets to memory
38 // locations.
39 
40 namespace vspace {
41 
42 enum ErrCode {
48 };
49 
50 template <typename T>
51 struct Result {
52  bool ok;
54  Result(T result) : ok(true), result(result) {
55  }
57  }
58 private:
60  static T result;
61  return result;
62  }
63 };
64 
65 struct Status {
67  bool ok() {
68  return err == ErrNone;
69  }
70  operator bool() {
71  return err == ErrNone;
72  }
74  }
75 };
76 
77 namespace internals {
78 
79 typedef size_t segaddr_t;
80 
81 typedef size_t vaddr_t;
82 
85 
86 static const int MAX_PROCESS = 64;
87 static const size_t METABLOCK_SIZE = 128 * 1024; // 128 KB
88 static const int LOG2_SEGMENT_SIZE = 28; // 256 MB
89 static const int LOG2_MAX_SEGMENTS = 10; // 256 GB
90 static const size_t MAX_SEGMENTS = 1 << LOG2_MAX_SEGMENTS;
91 static const size_t SEGMENT_SIZE = 1 << LOG2_SEGMENT_SIZE;
92 static const size_t SEGMENT_MASK = (SEGMENT_SIZE - 1);
93 
94 // This is a very basic spinlock implementation that does not guarantee
95 // fairness.
96 //
97 // TODO: add a wait queue and/or use futexes on Linux.
98 class FastLock {
99 private:
100 #ifdef HAVE_CPP_THREADS
101  std::atomic_flag _lock;
102  short _owner, _head, _tail;
103 #else
105 #endif
106 public:
107 #ifdef HAVE_CPP_THREADS
108  FastLock(vaddr_t offset = 0) : _owner(-1), _head(-1), _tail(-1) {
109  _lock.clear();
110  }
111 #else
113  }
114 #endif
115 #ifdef HAVE_CPP_THREADS
116  // We only need to define the copy constructur for the
117  // atomic version, as the std::atomic_flag constructor
118  // is deleted.
119  FastLock(const FastLock &other) {
120  _owner = other._owner;
121  _head = other._head;
122  _tail = other._tail;
123  _lock.clear();
124  }
125  FastLock &operator=(const FastLock &other) {
126  _owner = other._owner;
127  _head = other._head;
128  _tail = other._tail;
129  _lock.clear();
130  return *this;
131  }
132 #endif
133  void lock();
134  void unlock();
135 };
136 
137 extern size_t config[4];
138 
139 void init_flock_struct(
140  struct flock &lock_info, size_t offset, size_t len, bool lock);
141 void lock_file(int fd, size_t offset, size_t len = 1);
142 void unlock_file(int fd, size_t offset, size_t len = 1);
143 
144 void lock_metapage();
145 void unlock_metapage();
146 void init_metapage(bool create);
147 
148 typedef int ipc_signal_t;
149 
150 bool send_signal(int processno, ipc_signal_t sig = 0, bool lock = true);
151 ipc_signal_t check_signal(bool resume = false, bool lock = true);
152 void accept_signals();
153 ipc_signal_t wait_signal(bool lock = true);
155 
156 struct Block;
157 struct MetaPage;
158 struct ProcessChannel;
159 
161  Waiting = 0,
162  Pending = 1,
163  Accepted = 2,
164 };
165 
166 struct ProcessInfo {
167  pid_t pid;
168  SignalState sigstate; // are there pending signals?
170 #ifdef HAVE_CPP_THREADS
171  int next; // next in queue waiting for a lock.
172 #endif
173 };
174 
175 struct MetaPage {
176  size_t config_header[4];
181 };
182 
183 // We use pipes/fifos to signal processes. For each process, fd_read is
184 // where the process reads from and fd_write is where other processes
185 // signal the reading process. Only single bytes are sent across each
186 // channel. Because the effect of concurrent writes is undefined, bytes
187 // must only be written by a single process at the time. This is usually
188 // the case when the sending process knows that the receiving process is
189 // waiting for a resource that the sending process currently holds. See
190 // the Semaphore implementation for an example.
191 
194 };
195 
196 struct Block {
197  // the lowest bits of prev encode whether we are looking at an
198  // allocated or free block. For an allocared block, the lowest bits
199  // are 01. For a free block, they are 00 (for a null reference (==
200  // -1), they are 11.
201  //
202  // For allocated blocks, the higher bits encode the segment and the
203  // log2 of the block size (level). This requires LOG2_MAX_SEGMENTS +
204  // log2(sizeof(vaddr_t) * 8) + 2 bits.
205  //
206  // For free blocks, the level is stored in the data field.
209  size_t data[1];
210  bool is_free() {
211  return (prev & 3) != 1;
212  }
213  int level() {
214  if (is_free())
215  return (int) data[0];
216  else
217  return (int) (prev >> (LOG2_MAX_SEGMENTS + 2));
218  }
219  void mark_as_allocated(vaddr_t vaddr, int level) {
220  vaddr_t bits = level;
221  bits <<= LOG2_MAX_SEGMENTS;
222  bits |= vaddr >> LOG2_SEGMENT_SIZE;
223  bits <<= 2;
224  bits |= 1;
225  prev = bits;
226  next = 0;
227  }
228  void mark_as_free(int level) {
229  data[0] = level;
230  }
231 };
232 
233 struct VSeg {
234  unsigned char *base;
235  inline Block *block_ptr(segaddr_t addr) {
236  return (Block *) (base + addr);
237  }
238  bool is_free(segaddr_t addr) {
239  Block *block = block_ptr(addr);
240  return block->is_free();
241  }
242  inline void *ptr(segaddr_t addr) {
243  return (void *) (base + addr);
244  }
245  VSeg() : base(NULL) {
246  }
247  VSeg(void *base) : base((unsigned char *) base) {
248  }
249 };
250 
251 struct VMem {
254  int fd;
255  FILE *file_handle;
256  int current_process; // index into process table
257  vaddr_t *freelist; // reference to metapage information
261  return segments[vaddr >> LOG2_SEGMENT_SIZE];
262  }
263  inline size_t segment_no(vaddr_t vaddr) {
264  return vaddr >> LOG2_SEGMENT_SIZE;
265  }
266  inline vaddr_t vaddr(size_t segno, segaddr_t addr) {
267  return (segno << LOG2_SEGMENT_SIZE) | addr;
268  }
270  if (vaddr == VADDR_NULL)
271  return SEGADDR_NULL;
272  return vaddr & SEGMENT_MASK;
273  }
275  if (vaddr == VADDR_NULL)
276  return NULL;
277  return (Block *) (segment(vaddr).base + segaddr(vaddr));
278  }
280  int seg = vaddr >> LOG2_SEGMENT_SIZE;
281  if (segments[seg].base != NULL)
282  return;
283  segments[seg] = mmap_segment(seg);
284  }
285  inline void *to_ptr(vaddr_t vaddr) {
286  if (vaddr == VADDR_NULL)
287  return NULL;
289  return segment(vaddr).ptr(segaddr(vaddr));
290  }
291  size_t filesize();
292  Status init(int fd);
293  Status init();
294  Status init(const char *path);
295  void deinit();
296  void *mmap_segment(int seg);
297  void add_segment();
298 };
299 
301 
302 inline Block *block_ptr(vaddr_t vaddr) {
303  return vmem.block_ptr(vaddr);
304 }
305 
306 #ifdef HAVE_CPP_THREADS
307 struct refcount_t {
308  std::atomic<ptrdiff_t> rc;
309  refcount_t(ptrdiff_t init) : rc(init) {
310  }
311  ptrdiff_t inc(vaddr_t vaddr) {
312  rc++;
313  return (ptrdiff_t) rc;
314  }
315  ptrdiff_t dec(vaddr_t vaddr) {
316  rc--;
317  return (ptrdiff_t) rc;
318  }
319 };
320 #else
321 struct refcount_t {
322  ptrdiff_t rc;
323  static void lock(vaddr_t vaddr) {
324  lock_file(vmem.fd, METABLOCK_SIZE + vaddr);
325  }
326  static void unlock(vaddr_t vaddr) {
327  unlock_file(vmem.fd, METABLOCK_SIZE + vaddr);
328  }
329  refcount_t(ptrdiff_t init) : rc(init) {
330  }
331  ptrdiff_t inc(vaddr_t vaddr) {
332  lock(vaddr);
333  ptrdiff_t result = ++rc;
334  unlock(vaddr);
335  return result;
336  }
337  ptrdiff_t dec(vaddr_t vaddr) {
338  lock(vaddr);
339  ptrdiff_t result = --rc;
340  unlock(vaddr);
341  return result;
342  }
343 };
344 #endif
345 
346 static inline int find_level(size_t size) {
347  int level = 0;
348  while ((1 << (level + 8)) <= size)
349  level += 8;
350  while ((1 << level) < size)
351  level++;
352  return level;
353 }
354 
355 static inline segaddr_t find_buddy(segaddr_t addr, int level) {
356  return addr ^ (1 << level);
357 }
358 
359 void vmem_free(vaddr_t vaddr);
360 vaddr_t vmem_alloc(size_t size);
361 
362 static inline vaddr_t allocated_ptr_to_vaddr(void *ptr) {
363  char *addr = (char *) ptr - sizeof(Block);
364  vaddr_t info = ((Block *) addr)->prev;
365  int seg = info & (MAX_SEGMENTS - 1);
366  unsigned char *segstart = vmem.segments[seg].base;
367  size_t offset = (unsigned char *) ptr - segstart;
368  return (seg << LOG2_SEGMENT_SIZE) | offset;
369 }
370 
371 class Mutex {
372 private:
373  int _owner;
376 
377 public:
379  }
380  ~Mutex() {
381  vmem_free(_lock);
382  }
383  void lock() {
384  if (_owner == vmem.current_process) {
385  _locklevel++;
386  } else {
389  _locklevel = 1;
390  }
391  }
392  void unlock() {
393  if (--_locklevel == 0) {
395  _owner = -1;
397  }
398  }
399 };
400 
401 }; // namespace internals
402 
403 static inline Status vmem_init() {
404  return internals::vmem.init();
405 }
406 
407 static inline void vmem_deinit() {
409 }
410 
411 template <typename T>
412 struct VRef {
413 private:
416  }
417 public:
418  VRef() : vaddr(internals::VADDR_NULL) {
419  }
421  return VRef(vaddr);
422  }
423  size_t offset() const {
424  return vaddr;
425  }
426  bool operator==(VRef<T> other) {
427  return vaddr == other.vaddr;
428  }
429  bool operator!=(VRef<T> other) {
430  return vaddr != other.vaddr;
431  }
432  operator bool() const {
433  return vaddr != internals::VADDR_NULL;
434  }
435  bool is_null() {
436  return vaddr == internals::VADDR_NULL;
437  }
438  VRef(void *ptr) {
440  }
441  void *to_ptr() const {
442  return internals::vmem.to_ptr(vaddr);
443  }
444  T *as_ptr() const {
445  return (T *) to_ptr();
446  }
447  T &as_ref() const {
448  return *(T *) to_ptr();
449  }
450  T &operator*() const {
451  return *(T *) to_ptr();
452  }
454  return (T *) to_ptr();
455  }
457  vaddr = other.vaddr;
458  return *this;
459  }
460  T &operator[](size_t index) {
461  return as_ptr()[index];
462  }
463  template <typename U>
465  return VRef<U>::from_vaddr(vaddr);
466  }
467  static VRef<T> alloc(size_t n = 1) {
468  return VRef<T>(internals::vmem_alloc(n * sizeof(T)));
469  }
470  void free() {
471  as_ptr()->~T(); // explicitly call destructor
474  }
475 };
476 
477 template <>
478 struct VRef<void> {
479 private:
482  }
483 
484 public:
485  VRef() : vaddr(internals::VADDR_NULL) {
486  }
488  return VRef(vaddr);
489  }
490  size_t offset() const {
491  return vaddr;
492  }
493  operator bool() const {
494  return vaddr != internals::VADDR_NULL;
495  }
496  bool operator==(VRef<void> other) {
497  return vaddr == other.vaddr;
498  }
499  bool operator!=(VRef<void> other) {
500  return vaddr != other.vaddr;
501  }
502  bool is_null() {
503  return vaddr == internals::VADDR_NULL;
504  }
505  VRef(void *ptr) {
507  }
508  void *to_ptr() const {
509  return internals::vmem.to_ptr(vaddr);
510  }
511  void *as_ptr() const {
512  return (void *) to_ptr();
513  }
515  vaddr = other.vaddr;
516  return *this;
517  }
518  template <typename U>
520  return VRef<U>::from_vaddr(vaddr);
521  }
522  static VRef<void> alloc(size_t n = 1) {
524  }
525  void free() {
528  }
529 };
530 
531 template <typename T>
534 }
535 
536 template <typename T>
539  new (result.to_ptr()) T();
540  return result;
541 }
542 
543 template <typename T>
546  return result;
547 }
548 
549 template <typename T>
550 VRef<T> vnew_array(size_t n) {
552  T *ptr = result.as_ptr();
553  for (size_t i = 0; i < n; i++) {
554  new (ptr + i) T();
555  }
556  return result;
557 }
558 
559 template <typename T>
562  return result;
563 }
564 
565 template <typename T, typename Arg>
566 VRef<T> vnew(Arg arg) {
568  new (result.to_ptr()) T(arg);
569  return result;
570 }
571 
572 template <typename T, typename Arg1, typename Arg2>
573 VRef<T> vnew(Arg1 arg1, Arg2 arg2) {
575  new (result.to_ptr()) T(arg1, arg2);
576  return result;
577 }
578 
579 template <typename T, typename Arg1, typename Arg2, typename Arg3>
580 VRef<T> vnew(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
582  new (result.to_ptr()) T(arg1, arg2, arg3);
583  return result;
584 }
585 
586 template <typename T, typename Arg1, typename Arg2, typename Arg3,
587  typename Arg4>
588 VRef<T> vnew(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) {
590  new (result.to_ptr()) T(arg1, arg2, arg3, arg4);
591  return result;
592 }
593 
594 template <typename T, typename Arg1, typename Arg2, typename Arg3,
595  typename Arg4, typename Arg5>
596 VRef<T> vnew(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) {
598  new (result.to_ptr()) T(arg1, arg2, arg3, arg4, arg5);
599  return result;
600 }
601 
602 template <typename T>
603 struct ZRef {
604 private:
605  struct RefCounted {
607 #if __cplusplus >= 201100
608  alignas(T)
609 #endif
610  char data[sizeof(T)];
611  RefCounted() : rc(1) {
612  }
613  };
616  return ((RefCounted *) (internals::vmem.to_ptr(vaddr)))->rc;
617  }
618  void *to_ptr() {
619  return &(((RefCounted *) (internals::vmem.to_ptr(vaddr)))->data);
620  }
621 
622 public:
623  ZRef() : vaddr(internals::VADDR_NULL) {
624  }
626  }
627  operator bool() {
628  return vaddr != internals::VADDR_NULL;
629  }
630  bool is_null() {
631  return vaddr == internals::VADDR_NULL;
632  }
633  ZRef(void *ptr) {
635  }
636  T *as_ptr() const {
637  return (T *) to_ptr();
638  }
639  T &as_ref() const {
640  return *(T *) to_ptr();
641  }
642  T &operator*() const {
643  return *(T *) to_ptr();
644  }
646  return (T *) to_ptr();
647  }
649  vaddr = other.vaddr;
650  }
651  template <typename U>
652  ZRef<U> cast() const {
653  return ZRef<U>(vaddr);
654  }
655  void retain() {
656  refcount().inc(vaddr);
657  }
658  void release() {
659  if (refcount().dec(vaddr) == 0) {
660  as_ref().~T();
662  }
663  }
664  void free() {
665  as_ptr()->~T(); // explicitly call destructor
668  }
670  return internals::vmem_alloc(sizeof(RefCounted));
671  }
672 };
673 
674 template <typename T>
677 }
678 
679 template <typename T>
682  new (result.to_ptr()) T();
683  return result;
684 }
685 
686 template <typename T>
689  return result;
690 }
691 
692 template <typename T>
693 ZRef<T> znew_array(size_t n) {
695  T *ptr = result.as_ptr();
696  for (size_t i = 0; i < n; i++) {
697  new (ptr + i) T();
698  }
699  return result;
700 }
701 
702 template <typename T>
705  return result;
706 }
707 
708 template <typename T, typename Arg>
709 ZRef<T> znew(Arg arg) {
711  new (result.to_ptr()) T(arg);
712  return result;
713 }
714 
715 template <typename T, typename Arg1, typename Arg2>
716 ZRef<T> znew(Arg1 arg1, Arg2 arg2) {
718  new (result.to_ptr()) T(arg1, arg2);
719  return result;
720 }
721 
722 template <typename T, typename Arg1, typename Arg2, typename Arg3>
723 ZRef<T> znew(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
725  new (result.to_ptr()) T(arg1, arg2, arg3);
726  return result;
727 }
728 
729 class VString {
730 private:
732  size_t _len;
733 
734 public:
735  VString(const char *s) {
736  _len = strlen(s);
737  _buffer = vnew_uninitialized_array<char>(_len + 1);
738  strcpy(_buffer.as_ptr(), s);
739  }
740  VString(const char *s, size_t len) {
741  _len = len;
742  _buffer = vnew_uninitialized_array<char>(len + 1);
743  char *buffer = _buffer.as_ptr();
744  memcpy(buffer, s, len);
745  buffer[len] = '\0';
746  }
747  VString(size_t len) {
748  _len = len;
749  _buffer = vnew_uninitialized_array<char>(len + 1);
750  _buffer[len] = '\0';
751  }
753  _buffer.free();
754  }
755  size_t len() const {
756  return _len;
757  }
759  return vnew<VString>(_buffer.as_ptr(), _len);
760  }
761  const char *str() const {
762  return _buffer.as_ptr();
763  }
764 };
765 
766 static inline VRef<VString> vstring(const char *s) {
767  return vnew<VString>(s);
768 }
769 
770 static inline VRef<VString> vstring(const char *s, size_t len) {
771  return vnew<VString>(s, len);
772 }
773 
774 static inline VRef<VString> vstring(size_t len) {
775  return vnew<VString>(len);
776 }
777 
778 
779 template <typename Spec>
780 class VMap {
781 private:
782  typedef typename Spec::Key K;
783  typedef typename Spec::Value V;
784  struct Node {
786  size_t hash;
789  };
792  size_t _nbuckets;
793 
794  void _lock_bucket(size_t b) {
795  _locks[b].lock();
796  }
797  void _unlock_bucket(size_t b) {
798  _locks[b].unlock();
799  }
800 
801 public:
802  VMap(size_t size = 1024);
803  ~VMap();
804  bool add(VRef<K> key, VRef<V> value, VRef<K> &oldkey, VRef<V> &oldvalue,
805  bool replace = true);
806  bool add(VRef<K> key, VRef<V> value, bool replace = true) {
807  VRef<K> oldkey;
808  VRef<V> oldvalue;
809  return add(key, value, oldkey, oldvalue, replace);
810  }
811  bool remove(VRef<K> key, VRef<K> &oldkey, VRef<V> &oldvalue);
812  bool remove(VRef<K> key) {
813  VRef<K> oldkey;
814  VRef<V> oldvalue;
815  return remove(key, oldkey, oldvalue);
816  }
817  bool find(VRef<K> key, VRef<V> &value);
819  VRef<V> value;
820  if (find(key, value))
821  return value;
822  else
823  return vnull<V>();
824  }
825 };
826 
827 template <typename Spec>
829  using namespace internals;
830  _nbuckets = 8;
831  while (_nbuckets < size)
832  _nbuckets *= 2;
833  _buckets = vnew_array<VRef<Node> >(_nbuckets);
834  _locks = vnew_uninitialized_array<FastLock>(_nbuckets);
835  for (size_t i = 0; i < _nbuckets; i++)
836  _locks[i]
837  = FastLock(METABLOCK_SIZE + _locks.offset() + sizeof(FastLock) * i);
838 }
839 
840 template <typename Spec>
842  for (size_t b = 0; b < _nbuckets; b++) {
843  _lock_bucket(b);
844  VRef<Node> node = _buckets[b];
845  while (node) {
846  Node *node_ptr = node.as_ptr();
847  VRef<Node> next = node_ptr->next;
848  Spec::free_key(node_ptr->key);
849  Spec::free_value(node_ptr->value);
850  node.free();
851  node = next;
852  }
853  _unlock_bucket(b);
854  }
855  _buckets.free();
856  _locks.free();
857 }
858 
859 template <typename Spec>
860 bool VMap<Spec>::add(VRef<K> key, VRef<V> value, VRef<K> &oldkey,
861  VRef<V> &oldvalue, bool replace) {
862  size_t hash = Spec::hash(key.as_ptr());
863  size_t b = hash & (_nbuckets - 1);
864  _lock_bucket(b);
865  VRef<Node> node = _buckets[b];
866  VRef<Node> last = vnull<Node>();
867  while (!node.is_null()) {
868  Node *node_ptr = node.as_ptr();
869  if (hash == node_ptr->hash
870  && Spec::equal(key.as_ptr(), node_ptr->key.as_ptr())) {
871  value = node_ptr->value;
872  if (!last.is_null()) {
873  // move to front
874  last->next = node_ptr->next;
875  node_ptr->next = _buckets[b];
876  _buckets[b] = node;
877  }
878  oldkey = node_ptr->key;
879  oldvalue = node_ptr->value;
880  if (replace) {
881  node_ptr->key = key;
882  node_ptr->value = value;
883  }
884  _unlock_bucket(b);
885  return false;
886  }
887  last = node;
888  node = node->next;
889  }
890  node = vnew<Node>();
891  Node *node_ptr = node.as_ptr();
892  node_ptr->hash = hash;
893  node_ptr->key = key;
894  node_ptr->value = value;
895  node_ptr->next = _buckets[b];
896  _buckets[b] = node;
897  oldkey = key;
898  oldvalue = value;
899  _unlock_bucket(b);
900  return true;
901 }
902 
903 template <typename Spec>
904 bool VMap<Spec>::remove(VRef<K> key, VRef<K> &oldkey, VRef<V> &oldvalue) {
905  size_t hash = Spec::hash(key.as_ptr());
906  size_t b = hash & (_nbuckets - 1);
907  _lock_bucket(b);
908  VRef<Node> node = _buckets[b];
909  VRef<Node> last = vnull<Node>();
910  while (!node.is_null()) {
911  Node *node_ptr = node.as_ptr();
912  if (hash == node_ptr->hash
913  && Spec::equal(key.as_ptr(), node_ptr->key.as_ptr())) {
914  oldkey = node_ptr->key;
915  oldvalue = node_ptr->value;
916  // remove from list
917  if (last.is_null()) {
918  _buckets[b] = node_ptr->next;
919  } else {
920  last->next = node_ptr->next;
921  }
922  _unlock_bucket(b);
923  return true;
924  }
925  last = node;
926  node = node->next;
927  }
928  _unlock_bucket(b);
929  return false;
930 }
931 
932 template <typename Spec>
933 bool VMap<Spec>::find(VRef<K> key, VRef<V> &value) {
934  size_t hash = Spec::hash(key.as_ptr());
935  size_t b = hash & (_nbuckets - 1);
936  _lock_bucket(b);
937  VRef<Node> node = _buckets[b];
938  VRef<Node> last = vnull<Node>();
939  while (!node.is_null()) {
940  Node *node_ptr = node.as_ptr();
941  if (hash == node_ptr->hash
942  && Spec::equal(key.as_ptr(), node_ptr->key.as_ptr())) {
943  value = node_ptr->value;
944  // move to front
945  if (!last.is_null()) {
946  last->next = node_ptr->next;
947  node_ptr->next = _buckets[b];
948  }
949  _buckets[b] = node;
950  _unlock_bucket(b);
951  return true;
952  }
953  last = node;
954  node = node->next;
955  }
956  _unlock_bucket(b);
957  return false;
958 }
959 
960 struct DictSpec {
961  typedef VString Key;
962  typedef VString Value;
963  static size_t hash(const VString *s) {
964  // DJB hash
965  size_t len = s->len();
966  const char *str = s->str();
967  size_t hash = 5381;
968  for (size_t i = 0; i < len; i++) {
969  hash = 33 * hash + str[i];
970  }
971  return hash;
972  }
973  static bool equal(const VString *s1, const VString *s2) {
974  if (s1->len() != s2->len())
975  return false;
976  size_t len = s1->len();
977  const char *str1 = s1->str(), *str2 = s2->str();
978  for (size_t i = 0; i < len; i++) {
979  if (str1[i] != str2[i])
980  return false;
981  }
982  return true;
983  }
984  // By default, we do not make assumptions about ownership. It is
985  // up to the caller to free keys and values if needed or to
986  // define appropriate `free_key()` and `free_value()` functions
987  // that work. Note in particular that keys and values may occur
988  // more than once in a map and if that happens, they must not
989  // be freed multiple times.
990  static void free_key(VRef<Key> key) {
991  // do nothing
992  }
993  static void free_value(VRef<Value> value) {
994  // do nothing
995  }
996 };
997 
999 
1000 pid_t fork_process();
1001 
1002 #ifdef HAVE_CPP_THREADS
1004 #else
1006 #endif
1007 
1009 
1010 class Semaphore {
1011 private:
1012  int _owner;
1015  int _head, _tail;
1016  void next(int &index) {
1018  index = 0;
1019  else
1020  index++;
1021  }
1022  size_t _value;
1024  bool _idle() {
1025  return _head == _tail;
1026  }
1027  template <typename T>
1028  friend class SyncVar;
1029 
1030 public:
1031  Semaphore(size_t value = 0) :
1032  _owner(0), _head(0), _tail(0), _value(value), _lock() {
1033  }
1034  size_t value() {
1035  return _value;
1036  }
1037  void post();
1038  bool try_wait();
1039  void wait();
1040  bool start_wait(internals::ipc_signal_t sig = 0);
1041  bool stop_wait();
1042 };
1043 
1044 template <typename T>
1045 class Queue {
1046 private:
1047  struct Node {
1050  };
1053  bool _bounded;
1058  if (_head->next.is_null()) {
1059  _head = _tail = vnull<Node>();
1060  } else {
1061  _head = _head->next;
1062  }
1063  return result;
1064  }
1065  void push(VRef<Node> node) {
1066  node->next = vnull<Node>();
1067  if (_tail.is_null()) {
1068  _head = _tail = node;
1069  } else {
1070  _tail->next = node;
1071  _tail = node;
1072  }
1073  }
1074  template <typename U>
1075  friend class EnqueueEvent;
1076  template <typename U>
1077  friend class DequeueEvent;
1078 
1079  void enqueue_nowait(T item) {
1080  _lock.lock();
1081  VRef<Node> node = vnew<Node>();
1082  node->data = item;
1083  push(node);
1084  _lock.unlock();
1085  _incoming.post();
1086  }
1088  _lock.lock();
1089  VRef<Node> node = pop();
1090  T result;
1091  result = node->data;
1092  node.free();
1093  _lock.unlock();
1094  if (_bounded)
1095  _outgoing.post();
1096  return result;
1097  }
1098 
1099 public:
1100  Queue(size_t bound = 0) :
1101  _incoming(0),
1102  _outgoing(bound),
1103  _bounded(bound != 0),
1104  _head(),
1105  _tail(),
1106  _lock() {
1107  }
1108  void enqueue(T item) {
1109  if (_bounded)
1110  _outgoing.wait();
1111  enqueue_nowait(item);
1112  }
1113  bool try_enqueue(T item) {
1114  if (_bounded && _outgoing.try_wait()) {
1115  enqueue_nowait(item);
1116  return true;
1117  } else {
1118  return false;
1119  }
1120  }
1122  _incoming.wait();
1123  return dequeue_nowait();
1124  }
1126  if (_incoming.try_wait())
1127  return Result<T>(dequeue_nowait());
1128  else
1129  return Result<T>();
1130  }
1131 };
1132 
1133 template <typename T>
1134 class SyncVar {
1135 private:
1138  bool _set;
1140  template <typename U>
1141  friend class SyncReadEvent;
1143  void stop_wait();
1144 public:
1145  SyncVar() : _set(false) { }
1146  T read();
1147  Result<T> try_read();
1148  bool write(T value);
1149  bool test() {
1150  return _set;
1151  }
1152 };
1153 
1154 template <typename T>
1156  _lock.lock();
1157  if (_set) {
1158  internals::send_signal(internals::vmem.current_process, sig);
1159  _lock.unlock();
1160  return true;
1161  }
1162  if (_sem.is_null()) {
1163  _sem = vnew<Semaphore>();
1164  }
1165  bool result = _sem->start_wait(sig);
1166  _lock.unlock();
1167  return result;
1168 }
1169 
1170 template <typename T>
1172  _lock.lock();
1173  if (!_sem.is_null()) {
1174  _sem->stop_wait();
1175  if (!_sem->_idle())
1176  _sem->post();
1177  }
1178  _lock.unlock();
1179 }
1180 
1181 template <typename T>
1183  _lock.lock();
1184  if (_set) {
1185  _lock.unlock();
1186  return _value;
1187  }
1188  if (_sem.is_null()) {
1189  _sem = vnew<Semaphore>();
1190  }
1191  // We can't wait inside the lock without deadlocking; but waiting outside
1192  // could cause a race condition with _sem being freed due to being idle.
1193  // Thus, we use start_wait() to insert ourselves into the queue, then
1194  // use wait_signal() outside the lock to complete waiting.
1195  //
1196  // Note: start_wait() will not send a signal to self, as _set is
1197  // false and therefore _sem->value() must be zero.
1198  _sem->start_wait(0);
1199  _lock.unlock();
1201  _lock.lock();
1202  if (_sem->_idle())
1203  _sem->post();
1204  else {
1205  _sem.free();
1206  _sem = vnull<Semaphore>();
1207  }
1208  _lock.unlock();
1209  return _value;
1210 }
1211 
1212 template <typename T>
1214  _lock.lock();
1215  Result<T> result = _set ? Result<T>(_value) : Result<T>();
1216  _lock.unlock();
1217  return result;
1218 }
1219 
1220 template <typename T>
1221 bool SyncVar<T>::write(T value) {
1222  _lock.lock();
1223  if (_set) {
1224  _lock.unlock();
1225  return false;
1226  }
1227  _set = true;
1228  _value = value;
1229  if (!_sem->_idle())
1230  _sem->post();
1231  _lock.unlock();
1232  return true;
1233 }
1234 
1235 class Event {
1236 private:
1238  friend class EventSet;
1239 public:
1240  virtual bool start_listen(internals::ipc_signal_t sig) = 0;
1241  virtual void stop_listen() = 0;
1242 };
1243 
1244 class EventSet {
1245 private:
1247 
1248 public:
1250  }
1251  void add(Event *event);
1252  void add(Event &event) {
1253  add(&event);
1254  }
1256  add(event);
1257  return *this;
1258  }
1260  add(event);
1261  return *this;
1262  }
1263  int wait();
1264 };
1265 
1266 class WaitSemaphoreEvent : public Event {
1267 private:
1269 
1270 public:
1272  }
1274  return _sem->start_wait(sig);
1275  }
1276  virtual void stop_listen() {
1277  _sem->stop_wait();
1278  }
1279  void complete() {
1280  }
1281 };
1282 
1283 template <typename T>
1284 class EnqueueEvent : public Event {
1285 private:
1287 
1288 public:
1289  EnqueueEvent(VRef<Queue<T> > queue) : _queue(queue) {
1290  }
1292  return _queue->_outgoing.start_wait(sig);
1293  }
1294  virtual void stop_listen() {
1295  _queue->_outgoing.stop_wait();
1296  }
1297  void complete(T item) {
1298  _queue->enqueue_nowait(item);
1299  }
1300 };
1301 
1302 template <typename T>
1303 class DequeueEvent : public Event {
1304 private:
1306 
1307 public:
1308  DequeueEvent(VRef<Queue<T> > queue) : _queue(queue) {
1309  }
1311  return _queue->_incoming.start_wait(sig);
1312  }
1313  virtual void stop_listen() {
1314  _queue->_incoming.stop_wait();
1315  }
1317  return _queue->dequeue_nowait();
1318  }
1319 };
1320 
1321 template <typename T>
1322 class SyncReadEvent : public Event {
1323 private:
1325 
1326 public:
1327  SyncReadEvent(VRef<SyncVar<T> > syncvar) : _syncvar(syncvar) {
1328  }
1330  return _syncvar->start_wait(sig);
1331  }
1332  virtual void stop_listen() {
1333  _syncvar->stop_wait();
1334  }
1336  return _syncvar->read();
1337  }
1338 };
1339 
1340 }; // namespace vspace
1341 #endif
1342 #endif
int size(const CanonicalForm &f, const Variable &v)
int size ( const CanonicalForm & f, const Variable & v )
Definition: cf_ops.cc:600
int level(const CanonicalForm &f)
int i
Definition: cfEzgcd.cc:132
return false
Definition: cfModGcd.cc:84
bool equal
Definition: cfModGcd.cc:4126
CanonicalForm b
Definition: cfModGcd.cc:4103
static CanonicalForm bound(const CFMatrix &M)
Definition: cf_linsys.cc:460
DequeueEvent(VRef< Queue< T > > queue)
Definition: vspace.h:1308
VRef< Queue< T > > _queue
Definition: vspace.h:1305
virtual void stop_listen()
Definition: vspace.h:1313
virtual bool start_listen(internals::ipc_signal_t sig)
Definition: vspace.h:1310
virtual void stop_listen()
Definition: vspace.h:1294
void complete(T item)
Definition: vspace.h:1297
VRef< Queue< T > > _queue
Definition: vspace.h:1286
virtual bool start_listen(internals::ipc_signal_t sig)
Definition: vspace.h:1291
EnqueueEvent(VRef< Queue< T > > queue)
Definition: vspace.h:1289
void add(Event *event)
Definition: vspace.cc:529
EventSet & operator<<(Event &event)
Definition: vspace.h:1259
void add(Event &event)
Definition: vspace.h:1252
EventSet & operator<<(Event *event)
Definition: vspace.h:1255
Event * _head
Definition: vspace.h:1246
Event * _tail
Definition: vspace.h:1246
Event * _next
Definition: vspace.h:1237
virtual void stop_listen()=0
virtual bool start_listen(internals::ipc_signal_t sig)=0
VRef< Node > pop()
Definition: vspace.h:1056
void enqueue(T item)
Definition: vspace.h:1108
Semaphore _incoming
Definition: vspace.h:1051
Queue(size_t bound=0)
Definition: vspace.h:1100
void push(VRef< Node > node)
Definition: vspace.h:1065
T dequeue_nowait()
Definition: vspace.h:1087
VRef< Node > next
Definition: vspace.h:1048
Semaphore _outgoing
Definition: vspace.h:1052
Result< T > try_dequeue()
Definition: vspace.h:1125
bool try_enqueue(T item)
Definition: vspace.h:1113
void enqueue_nowait(T item)
Definition: vspace.h:1079
bool _bounded
Definition: vspace.h:1053
VRef< Node > _head
Definition: vspace.h:1055
VRef< Node > _tail
Definition: vspace.h:1055
FastLock _lock
Definition: vspace.h:1054
int _waiting[internals::MAX_PROCESS+1]
Definition: vspace.h:1013
void next(int &index)
Definition: vspace.h:1016
bool start_wait(internals::ipc_signal_t sig=0)
Definition: vspace.cc:492
internals::ipc_signal_t _signals[internals::MAX_PROCESS+1]
Definition: vspace.h:1014
FastLock _lock
Definition: vspace.h:1023
size_t value()
Definition: vspace.h:1034
Semaphore(size_t value=0)
Definition: vspace.h:1031
bool try_wait()
Definition: vspace.cc:467
bool stop_wait()
Definition: vspace.cc:507
virtual bool start_listen(internals::ipc_signal_t sig)
Definition: vspace.h:1329
SyncReadEvent(VRef< SyncVar< T > > syncvar)
Definition: vspace.h:1327
virtual void stop_listen()
Definition: vspace.h:1332
VRef< SyncVar< T > > _syncvar
Definition: vspace.h:1324
VRef< Semaphore > _sem
Definition: vspace.h:1137
Result< T > try_read()
Definition: vspace.h:1213
FastLock _lock
Definition: vspace.h:1136
bool write(T value)
Definition: vspace.h:1221
bool test()
Definition: vspace.h:1149
void stop_wait()
Definition: vspace.h:1171
bool start_wait(internals::ipc_signal_t sig)
Definition: vspace.h:1155
bool remove(VRef< K > key, VRef< K > &oldkey, VRef< V > &oldvalue)
Definition: vspace.h:904
VRef< V > value
Definition: vspace.h:788
VRef< K > key
Definition: vspace.h:787
bool find(VRef< K > key, VRef< V > &value)
Definition: vspace.h:933
void _lock_bucket(size_t b)
Definition: vspace.h:794
Spec::Value V
Definition: vspace.h:783
bool remove(VRef< K > key)
Definition: vspace.h:812
Spec::Key K
Definition: vspace.h:782
VRef< VRef< Node > > _buckets
Definition: vspace.h:790
bool add(VRef< K > key, VRef< V > value, bool replace=true)
Definition: vspace.h:806
bool add(VRef< K > key, VRef< V > value, VRef< K > &oldkey, VRef< V > &oldvalue, bool replace=true)
Definition: vspace.h:860
void _unlock_bucket(size_t b)
Definition: vspace.h:797
VRef< internals::FastLock > _locks
Definition: vspace.h:791
VRef< Node > next
Definition: vspace.h:785
VRef< V > find(VRef< K > key)
Definition: vspace.h:818
size_t _nbuckets
Definition: vspace.h:792
VMap(size_t size=1024)
Definition: vspace.h:828
VRef< char > _buffer
Definition: vspace.h:731
VString(const char *s, size_t len)
Definition: vspace.h:740
VRef< VString > clone() const
Definition: vspace.h:758
VString(size_t len)
Definition: vspace.h:747
size_t _len
Definition: vspace.h:732
const char * str() const
Definition: vspace.h:761
size_t len() const
Definition: vspace.h:755
VString(const char *s)
Definition: vspace.h:735
WaitSemaphoreEvent(VRef< Semaphore > sem)
Definition: vspace.h:1271
virtual bool start_listen(internals::ipc_signal_t sig)
Definition: vspace.h:1273
virtual void stop_listen()
Definition: vspace.h:1276
VRef< Semaphore > _sem
Definition: vspace.h:1268
FastLock(vaddr_t offset=0)
Definition: vspace.h:112
return result
Definition: facAbsBiFact.cc:75
const CanonicalForm int s
Definition: facAbsFact.cc:51
const ExtensionInfo & info
< [in] sqrfree poly
STATIC_VAR poly last
Definition: hdegree.cc:1151
STATIC_VAR int offset
Definition: janet.cc:29
STATIC_VAR jList * T
Definition: janet.cc:30
NodeM * create()
Definition: janet.cc:757
ListNode * next
Definition: janet.h:31
char N base
Definition: ValueTraits.h:144
char * str(leftv arg)
Definition: shared.cc:704
void init()
Definition: lintree.cc:864
void drop_pending_signals()
void accept_signals()
Definition: vspace.cc:407
Block * block_ptr(vaddr_t vaddr)
Definition: vspace.h:302
void unlock_metapage()
Definition: vspace.cc:310
const vaddr_t VADDR_NULL
Definition: vspace.h:84
void init_flock_struct(struct flock &lock_info, size_t offset, size_t len, bool lock)
Definition: vspace.cc:285
size_t vaddr_t
Definition: vspace.h:81
void lock_file(int fd, size_t offset, size_t len)
Definition: vspace.cc:294
void vmem_free(vaddr_t vaddr)
Definition: vspace.cc:195
vaddr_t vmem_alloc(size_t size)
Definition: vspace.cc:243
static vaddr_t allocated_ptr_to_vaddr(void *ptr)
Definition: vspace.h:362
static const size_t MAX_SEGMENTS
Definition: vspace.h:90
vaddr_t freelist[LOG2_SEGMENT_SIZE+1]
Definition: vspace.h:178
static const size_t SEGMENT_SIZE
Definition: vspace.h:91
static const size_t METABLOCK_SIZE
Definition: vspace.h:87
static const int LOG2_SEGMENT_SIZE
Definition: vspace.h:88
ipc_signal_t wait_signal(bool lock)
Definition: vspace.cc:413
void lock_metapage()
Definition: vspace.cc:306
static const int LOG2_MAX_SEGMENTS
Definition: vspace.h:89
static const int MAX_PROCESS
Definition: vspace.h:86
static VMem & vmem
Definition: vspace.h:300
ProcessInfo process_info[MAX_PROCESS]
Definition: vspace.h:180
static segaddr_t find_buddy(segaddr_t addr, int level)
Definition: vspace.h:355
ipc_signal_t check_signal(bool resume, bool lock)
Definition: vspace.cc:370
void init_metapage(bool create)
Definition: vspace.cc:314
void unlock_file(int fd, size_t offset, size_t len)
Definition: vspace.cc:300
static const size_t SEGMENT_MASK
Definition: vspace.h:92
bool send_signal(int processno, ipc_signal_t sig, bool lock)
Definition: vspace.cc:347
static int find_level(size_t size)
Definition: vspace.h:346
const segaddr_t SEGADDR_NULL
Definition: vspace.h:83
size_t config[4]
Definition: vspace.cc:13
size_t segaddr_t
Definition: vspace.h:79
Definition: vspace.cc:9
pid_t fork_process()
Definition: vspace.cc:419
static void vmem_deinit()
Definition: vspace.h:407
ZRef< T > znew_uninitialized_array(size_t n)
Definition: vspace.h:703
VRef< T > vnull()
Definition: vspace.h:532
VRef< T > vnew_array(size_t n)
Definition: vspace.h:550
ZRef< T > znew_uninitialized()
Definition: vspace.h:687
ZRef< T > znew()
Definition: vspace.h:680
ZRef< T > znull()
Definition: vspace.h:675
ErrCode
Definition: vspace.h:42
@ ErrGeneral
Definition: vspace.h:44
@ ErrOS
Definition: vspace.h:47
@ ErrNone
Definition: vspace.h:43
@ ErrFile
Definition: vspace.h:45
@ ErrMMap
Definition: vspace.h:46
VRef< T > vnew_uninitialized_array(size_t n)
Definition: vspace.h:560
internals::Mutex Mutex
Definition: vspace.h:1008
VMap< DictSpec > VDict
Definition: vspace.h:998
VRef< T > vnew()
Definition: vspace.h:537
static VRef< VString > vstring(const char *s)
Definition: vspace.h:766
ZRef< T > znew_array(size_t n)
Definition: vspace.h:693
static Status vmem_init()
Definition: vspace.h:403
internals::Mutex FastLock
Definition: vspace.h:1005
VRef< T > vnew_uninitialized()
Definition: vspace.h:544
#define NULL
Definition: omList.c:12
static int index(p_Length length, p_Ord ord)
Definition: p_Procs_Impl.h:592
#define block
Definition: scanner.cc:666
int status int fd
Definition: si_signals.h:59
static void free_value(VRef< Value > value)
Definition: vspace.h:993
VString Key
Definition: vspace.h:961
static bool equal(const VString *s1, const VString *s2)
Definition: vspace.h:973
static size_t hash(const VString *s)
Definition: vspace.h:963
static void free_key(VRef< Key > key)
Definition: vspace.h:990
VString Value
Definition: vspace.h:962
T & default_value()
Definition: vspace.h:59
Result(T result)
Definition: vspace.h:54
bool ok()
Definition: vspace.h:67
ErrCode err
Definition: vspace.h:66
Status(ErrCode err)
Definition: vspace.h:73
size_t offset() const
Definition: vspace.h:490
bool operator!=(VRef< void > other)
Definition: vspace.h:499
static VRef< void > from_vaddr(internals::vaddr_t vaddr)
Definition: vspace.h:487
bool operator==(VRef< void > other)
Definition: vspace.h:496
VRef< U > cast()
Definition: vspace.h:519
void * to_ptr() const
Definition: vspace.h:508
static VRef< void > alloc(size_t n=1)
Definition: vspace.h:522
VRef(void *ptr)
Definition: vspace.h:505
void * as_ptr() const
Definition: vspace.h:511
internals::vaddr_t vaddr
Definition: vspace.h:480
VRef(internals::vaddr_t vaddr)
Definition: vspace.h:481
VRef< void > & operator=(VRef< void > other)
Definition: vspace.h:514
VRef< T > & operator=(VRef< T > other)
Definition: vspace.h:456
static VRef< T > alloc(size_t n=1)
Definition: vspace.h:467
T & operator[](size_t index)
Definition: vspace.h:460
size_t offset() const
Definition: vspace.h:423
VRef(void *ptr)
Definition: vspace.h:438
T & operator*() const
Definition: vspace.h:450
bool is_null()
Definition: vspace.h:435
T * as_ptr() const
Definition: vspace.h:444
VRef(internals::vaddr_t vaddr)
Definition: vspace.h:415
bool operator!=(VRef< T > other)
Definition: vspace.h:429
T & as_ref() const
Definition: vspace.h:447
VRef< U > cast()
Definition: vspace.h:464
static VRef< T > from_vaddr(internals::vaddr_t vaddr)
Definition: vspace.h:420
bool operator==(VRef< T > other)
Definition: vspace.h:426
void free()
Definition: vspace.h:470
void * to_ptr() const
Definition: vspace.h:441
internals::vaddr_t vaddr
Definition: vspace.h:414
T * operator->()
Definition: vspace.h:453
internals::refcount_t rc
Definition: vspace.h:606
char data[sizeof(T)]
Definition: vspace.h:610
ZRef< U > cast() const
Definition: vspace.h:652
ZRef(internals::vaddr_t vaddr)
Definition: vspace.h:625
T * as_ptr() const
Definition: vspace.h:636
bool is_null()
Definition: vspace.h:630
void * to_ptr()
Definition: vspace.h:618
T & as_ref() const
Definition: vspace.h:639
internals::refcount_t & refcount()
Definition: vspace.h:615
ZRef(void *ptr)
Definition: vspace.h:633
internals::vaddr_t vaddr
Definition: vspace.h:614
T * operator->()
Definition: vspace.h:645
static internals::vaddr_t alloc()
Definition: vspace.h:669
ZRef< T > & operator=(ZRef< T > other)
Definition: vspace.h:648
void release()
Definition: vspace.h:658
void retain()
Definition: vspace.h:655
T & operator*() const
Definition: vspace.h:642
void free()
Definition: vspace.h:664
void mark_as_free(int level)
Definition: vspace.h:228
void mark_as_allocated(vaddr_t vaddr, int level)
Definition: vspace.h:219
void ensure_is_mapped(vaddr_t vaddr)
Definition: vspace.h:279
size_t segment_no(vaddr_t vaddr)
Definition: vspace.h:263
void * mmap_segment(int seg)
Definition: vspace.cc:95
Block * block_ptr(vaddr_t vaddr)
Definition: vspace.h:274
VSeg segment(vaddr_t vaddr)
Definition: vspace.h:260
void * to_ptr(vaddr_t vaddr)
Definition: vspace.h:285
MetaPage * metapage
Definition: vspace.h:253
static VMem vmem_global
Definition: vspace.h:252
vaddr_t * freelist
Definition: vspace.h:257
VSeg segments[MAX_SEGMENTS]
Definition: vspace.h:258
vaddr_t vaddr(size_t segno, segaddr_t addr)
Definition: vspace.h:266
segaddr_t segaddr(vaddr_t vaddr)
Definition: vspace.h:269
ProcessChannel channels[MAX_PROCESS]
Definition: vspace.h:259
Status init(int fd)
Definition: vspace.cc:29
void * ptr(segaddr_t addr)
Definition: vspace.h:242
Block * block_ptr(segaddr_t addr)
Definition: vspace.h:235
bool is_free(segaddr_t addr)
Definition: vspace.h:238
unsigned char * base
Definition: vspace.h:234
VSeg(void *base)
Definition: vspace.h:247
static void lock(vaddr_t vaddr)
Definition: vspace.h:323
ptrdiff_t dec(vaddr_t vaddr)
Definition: vspace.h:337
refcount_t(ptrdiff_t init)
Definition: vspace.h:329
ptrdiff_t inc(vaddr_t vaddr)
Definition: vspace.h:331
static void unlock(vaddr_t vaddr)
Definition: vspace.h:326
#define assert(A)
Definition: svd_si.h:3