source: libcfa/src/concurrency/ready_subqueue.hfa @ e3bf4cf

ADTast-experimental
Last change on this file since e3bf4cf was 15c93d8, checked in by Thierry Delisle <tdelisle@…>, 2 years ago

Renamed ready-queue link fields to rdy_link

  • 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$ *)(
[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]34static 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]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;
[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
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.