- File:
-
- 1 edited
-
libcfa/src/concurrency/kernel_private.hfa (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/kernel_private.hfa
rfc59df78 rbfcf6b9 77 77 //----------------------------------------------------------------------------- 78 78 // I/O 79 $io_arbiter * create(void); 80 void destroy($io_arbiter *); 79 void ^?{}(io_context & this, bool ); 81 80 82 81 //======================================================================= 83 82 // Cluster lock API 84 83 //======================================================================= 84 // Cells use by the reader writer lock 85 // while not generic it only relies on a opaque pointer 86 struct __attribute__((aligned(128))) __scheduler_lock_id_t { 87 // Spin lock used as the underlying lock 88 volatile bool lock; 89 90 // Handle pointing to the proc owning this cell 91 // Used for allocating cells and debugging 92 __processor_id_t * volatile handle; 93 94 #ifdef __CFA_WITH_VERIFY__ 95 // Debug, check if this is owned for reading 96 bool owned; 97 #endif 98 }; 99 100 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t)); 101 85 102 // Lock-Free registering/unregistering of threads 86 103 // Register a processor to a given cluster and get its unique id in return 87 void register_proc_id( struct __processor_id_t *);104 unsigned doregister( struct __processor_id_t * proc ); 88 105 89 106 // Unregister a processor from a given cluster using its id, getting back the original pointer 90 void unregister_proc_id( struct __processor_id_t * proc ); 107 void unregister( struct __processor_id_t * proc ); 108 109 //----------------------------------------------------------------------- 110 // Cluster idle lock/unlock 111 static inline void lock(__cluster_idles & this) { 112 for() { 113 uint64_t l = this.lock; 114 if( 115 (0 == (l % 2)) 116 && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) 117 ) return; 118 Pause(); 119 } 120 } 121 122 static inline void unlock(__cluster_idles & this) { 123 /* paranoid */ verify( 1 == (this.lock % 2) ); 124 __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST ); 125 } 91 126 92 127 //======================================================================= … … 116 151 __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE); 117 152 } 118 119 // Cells use by the reader writer lock120 // while not generic it only relies on a opaque pointer121 struct __attribute__((aligned(128))) __scheduler_lock_id_t {122 // Spin lock used as the underlying lock123 volatile bool lock;124 125 // Handle pointing to the proc owning this cell126 // Used for allocating cells and debugging127 __processor_id_t * volatile handle;128 129 #ifdef __CFA_WITH_VERIFY__130 // Debug, check if this is owned for reading131 bool owned;132 #endif133 };134 135 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));136 153 137 154 //----------------------------------------------------------------------- … … 229 246 void ready_mutate_unlock( uint_fast32_t /* value returned by lock */ ); 230 247 231 //-----------------------------------------------------------------------232 // Lock-Free registering/unregistering of threads233 // Register a processor to a given cluster and get its unique id in return234 // For convenience, also acquires the lock235 static inline uint_fast32_t ready_mutate_register( struct __processor_id_t * proc ) {236 register_proc_id( proc );237 return ready_mutate_lock();238 }239 240 // Unregister a processor from a given cluster using its id, getting back the original pointer241 // assumes the lock is acquired242 static inline void ready_mutate_unregister( struct __processor_id_t * proc, uint_fast32_t last_s ) {243 ready_mutate_unlock( last_s );244 unregister_proc_id( proc );245 }246 247 //-----------------------------------------------------------------------248 // Cluster idle lock/unlock249 static inline void lock(__cluster_proc_list & this) {250 /* paranoid */ verify( ! __preemption_enabled() );251 252 // Start by locking the global RWlock so that we know no-one is253 // adding/removing processors while we mess with the idle lock254 ready_schedule_lock();255 256 // Simple counting lock, acquired, acquired by incrementing the counter257 // to an odd number258 for() {259 uint64_t l = this.lock;260 if(261 (0 == (l % 2))262 && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)263 ) return;264 Pause();265 }266 267 /* paranoid */ verify( ! __preemption_enabled() );268 }269 270 static inline void unlock(__cluster_proc_list & this) {271 /* paranoid */ verify( ! __preemption_enabled() );272 273 /* paranoid */ verify( 1 == (this.lock % 2) );274 // Simple couting lock, release by incrementing to an even number275 __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );276 277 // Release the global lock, which we acquired when locking278 ready_schedule_unlock();279 280 /* paranoid */ verify( ! __preemption_enabled() );281 }282 283 248 //======================================================================= 284 249 // Ready-Queue API 250 //----------------------------------------------------------------------- 251 // pop thread from the ready queue of a cluster 252 // returns 0p if empty 253 __attribute__((hot)) bool query(struct cluster * cltr); 254 285 255 //----------------------------------------------------------------------- 286 256 // push thread onto a ready queue for a cluster 287 257 // returns true if the list was previously empty, false otherwise 288 __attribute__((hot)) voidpush(struct cluster * cltr, struct $thread * thrd);289 290 //----------------------------------------------------------------------- 291 // pop thread from the local queuesof a cluster258 __attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd); 259 260 //----------------------------------------------------------------------- 261 // pop thread from the ready queue of a cluster 292 262 // returns 0p if empty 293 263 // May return 0p spuriously 294 __attribute__((hot)) struct $thread * pop_fast(struct cluster * cltr); 295 296 //----------------------------------------------------------------------- 297 // pop thread from any ready queue of a cluster 298 // returns 0p if empty 299 // May return 0p spuriously 300 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr); 301 302 //----------------------------------------------------------------------- 303 // search all ready queues of a cluster for any thread 264 __attribute__((hot)) struct $thread * pop(struct cluster * cltr); 265 266 //----------------------------------------------------------------------- 267 // pop thread from the ready queue of a cluster 304 268 // returns 0p if empty 305 269 // guaranteed to find any threads added before this call 306 __attribute__((hot)) struct $thread * pop_search(struct cluster * cltr); 270 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr); 271 272 //----------------------------------------------------------------------- 273 // remove thread from the ready queue of a cluster 274 // returns bool if it wasn't found 275 bool remove_head(struct cluster * cltr, struct $thread * thrd); 307 276 308 277 //----------------------------------------------------------------------- 309 278 // Increase the width of the ready queue (number of lanes) by 4 310 void ready_queue_grow (struct cluster * cltr );279 void ready_queue_grow (struct cluster * cltr, int target); 311 280 312 281 //----------------------------------------------------------------------- 313 282 // Decrease the width of the ready queue (number of lanes) by 4 314 void ready_queue_shrink(struct cluster * cltr );283 void ready_queue_shrink(struct cluster * cltr, int target); 315 284 316 285
Note:
See TracChangeset
for help on using the changeset viewer.