| [13c5e19] | 1 | #pragma once
 | 
|---|
 | 2 | 
 | 
|---|
 | 3 | #define __CFA_NO_SCHED_STATS__
 | 
|---|
 | 4 | 
 | 
|---|
| [e71e94a] | 5 | #include "limits.hfa"
 | 
|---|
| [7a2972b9] | 6 | 
 | 
|---|
| [f6fdfb14] | 7 | // Intrusives lanes which are used by the relaxed ready queue
 | 
|---|
| [2af1943] | 8 | union __attribute__((aligned(64))) __intrusive_lane_t {
 | 
|---|
 | 9 |         struct {
 | 
|---|
 | 10 |                 struct thread$ * prev;
 | 
|---|
| [2b96031] | 11 | 
 | 
|---|
| [2af1943] | 12 |                 // spin lock protecting the queue
 | 
|---|
 | 13 |                 volatile bool lock;
 | 
|---|
| [13c5e19] | 14 | 
 | 
|---|
| [2af1943] | 15 |                 __thread_desc_link anchor;
 | 
|---|
| [353aaba] | 16 | 
 | 
|---|
| [2af1943] | 17 |                 #if !defined(__CFA_NO_STATISTICS__)
 | 
|---|
 | 18 |                         unsigned cnt;
 | 
|---|
 | 19 |                 #endif
 | 
|---|
 | 20 |         } l;
 | 
|---|
 | 21 |         char __padding[192];
 | 
|---|
| [f6fdfb14] | 22 | };
 | 
|---|
| [2b96031] | 23 | 
 | 
|---|
| [f6fdfb14] | 24 | // Get the head pointer (one before the first element) from the anchor
 | 
|---|
| [e84ab3d] | 25 | static inline thread$ * mock_head(const __intrusive_lane_t & this) {
 | 
|---|
 | 26 |         thread$ * rhead = (thread$ *)(
 | 
|---|
| [15c93d8] | 27 |                 (uintptr_t)( &this.l.anchor ) - __builtin_offsetof( thread$, rdy_link )
 | 
|---|
| [f6fdfb14] | 28 |         );
 | 
|---|
 | 29 |         return rhead;
 | 
|---|
 | 30 | }
 | 
|---|
 | 31 | 
 | 
|---|
 | 32 | // Push a thread onto this lane
 | 
|---|
 | 33 | // returns true of lane was empty before push, false otherwise
 | 
|---|
| [e84ab3d] | 34 | static inline void push( __intrusive_lane_t & this, thread$ * node ) {
 | 
|---|
| [2af1943] | 35 |         /* paranoid */ verify( this.l.lock );
 | 
|---|
| [15c93d8] | 36 |         /* paranoid */ verify( node->rdy_link.next == 0p );
 | 
|---|
 | 37 |         /* paranoid */ verify( __atomic_load_n(&node->rdy_link.ts, __ATOMIC_RELAXED) == MAX  );
 | 
|---|
 | 38 |         /* paranoid */ verify( this.l.prev->rdy_link.next == 0p );
 | 
|---|
 | 39 |         /* paranoid */ verify( __atomic_load_n(&this.l.prev->rdy_link.ts, __ATOMIC_RELAXED)   == MAX  );
 | 
|---|
| [2af1943] | 40 |         if( this.l.anchor.next == 0p ) {
 | 
|---|
 | 41 |                 /* paranoid */ verify( this.l.anchor.next == 0p );
 | 
|---|
 | 42 |                 /* paranoid */ verify( __atomic_load_n(&this.l.anchor.ts, __ATOMIC_RELAXED) == MAX );
 | 
|---|
 | 43 |                 /* paranoid */ verify( __atomic_load_n(&this.l.anchor.ts, __ATOMIC_RELAXED) != 0  );
 | 
|---|
 | 44 |                 /* paranoid */ verify( this.l.prev == mock_head( this ) );
 | 
|---|
| [f6fdfb14] | 45 |         } else {
 | 
|---|
| [2af1943] | 46 |                 /* paranoid */ verify( this.l.anchor.next != 0p );
 | 
|---|
 | 47 |                 /* paranoid */ verify( __atomic_load_n(&this.l.anchor.ts, __ATOMIC_RELAXED) != MAX );
 | 
|---|
 | 48 |                 /* paranoid */ verify( __atomic_load_n(&this.l.anchor.ts, __ATOMIC_RELAXED) != 0  );
 | 
|---|
 | 49 |                 /* paranoid */ verify( this.l.prev != mock_head( this ) );
 | 
|---|
| [2b96031] | 50 |         }
 | 
|---|
 | 51 | 
 | 
|---|
| [f6fdfb14] | 52 |         // Get the relevant nodes locally
 | 
|---|
| [15c93d8] | 53 |         this.l.prev->rdy_link.next = node;
 | 
|---|
 | 54 |         __atomic_store_n(&this.l.prev->rdy_link.ts, rdtscl(), __ATOMIC_RELAXED);
 | 
|---|
| [2af1943] | 55 |         this.l.prev = node;
 | 
|---|
| [16fd826] | 56 |         #if !defined(__CFA_NO_STATISTICS__)
 | 
|---|
| [2af1943] | 57 |                 this.l.cnt++;
 | 
|---|
| [16fd826] | 58 |         #endif
 | 
|---|
| [f6fdfb14] | 59 | }
 | 
|---|
 | 60 | 
 | 
|---|
 | 61 | // Pop a thread from this lane (must be non-empty)
 | 
|---|
 | 62 | // returns popped
 | 
|---|
 | 63 | // returns true of lane was empty before push, false otherwise
 | 
|---|
| [e84ab3d] | 64 | static inline [* thread$, unsigned long long] pop( __intrusive_lane_t & this ) {
 | 
|---|
| [2af1943] | 65 |         /* paranoid */ verify( this.l.lock );
 | 
|---|
 | 66 |         /* paranoid */ verify( this.l.anchor.next != 0p );
 | 
|---|
 | 67 |         /* paranoid */ verify( __atomic_load_n(&this.l.anchor.ts, __ATOMIC_RELAXED) != MAX );
 | 
|---|
 | 68 |         /* paranoid */ verify( __atomic_load_n(&this.l.anchor.ts, __ATOMIC_RELAXED) != 0   );
 | 
|---|
| [f6fdfb14] | 69 | 
 | 
|---|
 | 70 |         // Get the relevant nodes locally
 | 
|---|
| [2af1943] | 71 |         thread$ * node = this.l.anchor.next;
 | 
|---|
| [15c93d8] | 72 |         this.l.anchor.next = node->rdy_link.next;
 | 
|---|
 | 73 |         __atomic_store_n(&this.l.anchor.ts, __atomic_load_n(&node->rdy_link.ts, __ATOMIC_RELAXED), __ATOMIC_RELAXED);
 | 
|---|
| [2af1943] | 74 |         bool is_empty = this.l.anchor.next == 0p;
 | 
|---|
| [15c93d8] | 75 |         node->rdy_link.next = 0p;
 | 
|---|
 | 76 |         __atomic_store_n(&node->rdy_link.ts, ULLONG_MAX, __ATOMIC_RELAXED);
 | 
|---|
| [16fd826] | 77 |         #if !defined(__CFA_NO_STATISTICS__)
 | 
|---|
| [2af1943] | 78 |                 this.l.cnt--;
 | 
|---|
| [16fd826] | 79 |         #endif
 | 
|---|
| [f6fdfb14] | 80 | 
 | 
|---|
 | 81 |         // Update head time stamp
 | 
|---|
| [2af1943] | 82 |         if(is_empty) this.l.prev = mock_head( this );
 | 
|---|
| [f6fdfb14] | 83 | 
 | 
|---|
| [2af1943] | 84 |         unsigned long long ats = __atomic_load_n(&this.l.anchor.ts, __ATOMIC_RELAXED);
 | 
|---|
| [15c93d8] | 85 |         /* paranoid */ verify( node->rdy_link.next == 0p );
 | 
|---|
 | 86 |         /* paranoid */ verify( __atomic_load_n(&node->rdy_link.ts , __ATOMIC_RELAXED) == MAX );
 | 
|---|
 | 87 |         /* paranoid */ verify( __atomic_load_n(&node->rdy_link.ts , __ATOMIC_RELAXED) != 0   );
 | 
|---|
| [5024df4] | 88 |         /* paranoid */ verify( ats != 0 );
 | 
|---|
 | 89 |         /* paranoid */ verify( (ats == MAX) == is_empty );
 | 
|---|
 | 90 |         return [node, ats];
 | 
|---|
| [f6fdfb14] | 91 | }
 | 
|---|
 | 92 | 
 | 
|---|
 | 93 | // Check whether or not list is empty
 | 
|---|
 | 94 | static inline bool is_empty(__intrusive_lane_t & this) {
 | 
|---|
| [2af1943] | 95 |         return this.l.anchor.next == 0p;
 | 
|---|
| [f6fdfb14] | 96 | }
 | 
|---|
 | 97 | 
 | 
|---|
 | 98 | // Return the timestamp
 | 
|---|
 | 99 | static inline unsigned long long ts(__intrusive_lane_t & this) {
 | 
|---|
| [8a5e357] | 100 |         // Cannot verify 'emptiness' here since it may not be locked
 | 
|---|
| [2af1943] | 101 |         /* paranoid */ verify(this.l.anchor.ts != 0);
 | 
|---|
 | 102 |         /* paranoid */ static_assert(__atomic_always_lock_free(sizeof(this.l.anchor.ts), &this.l.anchor.ts));
 | 
|---|
 | 103 |         return __atomic_load_n(&this.l.anchor.ts, __ATOMIC_RELAXED);
 | 
|---|
| [b2f3880] | 104 | }
 | 
|---|