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