source: libcfa/src/concurrency/ready_subqueue.hfa@ 4f102fa

ADT ast-experimental
Last change on this file since 4f102fa was 2af1943, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Small improvements to some of the alignment requirements in CFA runtime.

  • Property mode set to 100644
File size: 3.8 KB
RevLine 
[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]8union __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]25static inline thread$ * mock_head(const __intrusive_lane_t & this) {
26 thread$ * rhead = (thread$ *)(
[2af1943]27 (uintptr_t)( &this.l.anchor ) - __builtin_offsetof( thread$, 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]34static inline void push( __intrusive_lane_t & this, thread$ * node ) {
[2af1943]35 /* paranoid */ verify( this.l.lock );
[f6fdfb14]36 /* paranoid */ verify( node->link.next == 0p );
[5024df4]37 /* paranoid */ verify( __atomic_load_n(&node->link.ts, __ATOMIC_RELAXED) == MAX );
[2af1943]38 /* paranoid */ verify( this.l.prev->link.next == 0p );
39 /* paranoid */ verify( __atomic_load_n(&this.l.prev->link.ts, __ATOMIC_RELAXED) == MAX );
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
[2af1943]53 this.l.prev->link.next = node;
54 __atomic_store_n(&this.l.prev->link.ts, rdtscl(), __ATOMIC_RELAXED);
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]64static 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;
72 this.l.anchor.next = node->link.next;
73 __atomic_store_n(&this.l.anchor.ts, __atomic_load_n(&node->link.ts, __ATOMIC_RELAXED), __ATOMIC_RELAXED);
74 bool is_empty = this.l.anchor.next == 0p;
[f6fdfb14]75 node->link.next = 0p;
[5024df4]76 __atomic_store_n(&node->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);
[f6fdfb14]85 /* paranoid */ verify( node->link.next == 0p );
[5024df4]86 /* paranoid */ verify( __atomic_load_n(&node->link.ts , __ATOMIC_RELAXED) == MAX );
87 /* paranoid */ verify( __atomic_load_n(&node->link.ts , __ATOMIC_RELAXED) != 0 );
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
94static inline bool is_empty(__intrusive_lane_t & this) {
[2af1943]95 return this.l.anchor.next == 0p;
[f6fdfb14]96}
97
98// Return the timestamp
99static 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);
[8cd40bf]104}
Note: See TracBrowser for help on using the repository browser.