- File:
-
- 1 edited
-
libcfa/src/concurrency/kernel_private.hfa (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/kernel_private.hfa
rbfcf6b9 rfc59df78 77 77 //----------------------------------------------------------------------------- 78 78 // I/O 79 void ^?{}(io_context & this, bool ); 79 $io_arbiter * create(void); 80 void destroy($io_arbiter *); 80 81 81 82 //======================================================================= 82 83 // Cluster lock API 83 84 //======================================================================= 84 // Cells use by the reader writer lock85 // while not generic it only relies on a opaque pointer86 struct __attribute__((aligned(128))) __scheduler_lock_id_t {87 // Spin lock used as the underlying lock88 volatile bool lock;89 90 // Handle pointing to the proc owning this cell91 // Used for allocating cells and debugging92 __processor_id_t * volatile handle;93 94 #ifdef __CFA_WITH_VERIFY__95 // Debug, check if this is owned for reading96 bool owned;97 #endif98 };99 100 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));101 102 85 // Lock-Free registering/unregistering of threads 103 86 // Register a processor to a given cluster and get its unique id in return 104 unsigned doregister( struct __processor_id_t * proc);87 void register_proc_id( struct __processor_id_t * ); 105 88 106 89 // Unregister a processor from a given cluster using its id, getting back the original pointer 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 } 90 void unregister_proc_id( struct __processor_id_t * proc ); 126 91 127 92 //======================================================================= … … 151 116 __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE); 152 117 } 118 119 // Cells use by the reader writer lock 120 // while not generic it only relies on a opaque pointer 121 struct __attribute__((aligned(128))) __scheduler_lock_id_t { 122 // Spin lock used as the underlying lock 123 volatile bool lock; 124 125 // Handle pointing to the proc owning this cell 126 // Used for allocating cells and debugging 127 __processor_id_t * volatile handle; 128 129 #ifdef __CFA_WITH_VERIFY__ 130 // Debug, check if this is owned for reading 131 bool owned; 132 #endif 133 }; 134 135 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t)); 153 136 154 137 //----------------------------------------------------------------------- … … 246 229 void ready_mutate_unlock( uint_fast32_t /* value returned by lock */ ); 247 230 231 //----------------------------------------------------------------------- 232 // Lock-Free registering/unregistering of threads 233 // Register a processor to a given cluster and get its unique id in return 234 // For convenience, also acquires the lock 235 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 pointer 241 // assumes the lock is acquired 242 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/unlock 249 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 is 253 // adding/removing processors while we mess with the idle lock 254 ready_schedule_lock(); 255 256 // Simple counting lock, acquired, acquired by incrementing the counter 257 // to an odd number 258 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 number 275 __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST ); 276 277 // Release the global lock, which we acquired when locking 278 ready_schedule_unlock(); 279 280 /* paranoid */ verify( ! __preemption_enabled() ); 281 } 282 248 283 //======================================================================= 249 284 // Ready-Queue API 250 285 //----------------------------------------------------------------------- 251 // pop thread from the ready queue of a cluster252 // returns 0p if empty253 __attribute__((hot)) bool query(struct cluster * cltr);254 255 //-----------------------------------------------------------------------256 286 // push thread onto a ready queue for a cluster 257 287 // returns true if the list was previously empty, false otherwise 258 __attribute__((hot)) boolpush(struct cluster * cltr, struct $thread * thrd);259 260 //----------------------------------------------------------------------- 261 // pop thread from the ready queueof a cluster288 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd); 289 290 //----------------------------------------------------------------------- 291 // pop thread from the local queues of a cluster 262 292 // returns 0p if empty 263 293 // May return 0p spuriously 264 __attribute__((hot)) struct $thread * pop(struct cluster * cltr); 265 266 //----------------------------------------------------------------------- 267 // pop thread from the ready queue of a cluster 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 268 304 // returns 0p if empty 269 305 // guaranteed to find any threads added before this call 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); 306 __attribute__((hot)) struct $thread * pop_search(struct cluster * cltr); 276 307 277 308 //----------------------------------------------------------------------- 278 309 // Increase the width of the ready queue (number of lanes) by 4 279 void ready_queue_grow (struct cluster * cltr , int target);310 void ready_queue_grow (struct cluster * cltr); 280 311 281 312 //----------------------------------------------------------------------- 282 313 // Decrease the width of the ready queue (number of lanes) by 4 283 void ready_queue_shrink(struct cluster * cltr , int target);314 void ready_queue_shrink(struct cluster * cltr); 284 315 285 316
Note:
See TracChangeset
for help on using the changeset viewer.