- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/kernel_private.hfa
rdd4e2d7 r504a7dc 77 77 //----------------------------------------------------------------------------- 78 78 // I/O 79 void __kernel_io_startup ( cluster &, unsigned, bool );79 void __kernel_io_startup ( cluster &, int, bool ); 80 80 void __kernel_io_finish_start( cluster & ); 81 81 void __kernel_io_prepare_stop( cluster & ); … … 84 84 //----------------------------------------------------------------------------- 85 85 // Utils 86 #define KERNEL_STORAGE(T,X) static char storage_##X[sizeof(T)]86 #define KERNEL_STORAGE(T,X) __attribute((aligned(__alignof__(T)))) static char storage_##X[sizeof(T)] 87 87 88 88 static inline uint32_t __tls_rand() { … … 103 103 void unregister( struct cluster * cltr, struct processor * proc ); 104 104 105 //======================================================================= 106 // Cluster lock API 107 //======================================================================= 108 struct __attribute__((aligned(64))) __processor_id { 109 processor * volatile handle; 110 volatile bool lock; 111 }; 112 113 // Lock-Free registering/unregistering of threads 114 // Register a processor to a given cluster and get its unique id in return 115 unsigned doregister2( struct cluster * cltr, struct processor * proc ); 116 117 // Unregister a processor from a given cluster using its id, getting back the original pointer 118 void unregister2( struct cluster * cltr, struct processor * proc ); 119 120 //======================================================================= 121 // Reader-writer lock implementation 122 // Concurrent with doregister/unregister, 123 // i.e., threads can be added at any point during or between the entry/exit 124 125 //----------------------------------------------------------------------- 126 // simple spinlock underlying the RWLock 127 // Blocking acquire 128 static inline void __atomic_acquire(volatile bool * ll) { 129 while( __builtin_expect(__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST), false) ) { 130 while(__atomic_load_n(ll, (int)__ATOMIC_RELAXED)) 131 asm volatile("pause"); 132 } 133 /* paranoid */ verify(*ll); 134 } 135 136 // Non-Blocking acquire 137 static inline bool __atomic_try_acquire(volatile bool * ll) { 138 return !__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST); 139 } 140 141 // Release 142 static inline void __atomic_unlock(volatile bool * ll) { 143 /* paranoid */ verify(*ll); 144 __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE); 145 } 146 147 //----------------------------------------------------------------------- 148 // Reader side : acquire when using the ready queue to schedule but not 149 // creating/destroying queues 150 static inline void ready_schedule_lock( struct cluster * cltr, struct processor * proc) with(cltr->ready_lock) { 151 unsigned iproc = proc->id; 152 /*paranoid*/ verify(data[iproc].handle == proc); 153 /*paranoid*/ verify(iproc < ready); 154 155 // Step 1 : make sure no writer are in the middle of the critical section 156 while(__atomic_load_n(&lock, (int)__ATOMIC_RELAXED)) 157 asm volatile("pause"); 158 159 // Fence needed because we don't want to start trying to acquire the lock 160 // before we read a false. 161 // Not needed on x86 162 // std::atomic_thread_fence(std::memory_order_seq_cst); 163 164 // Step 2 : acquire our local lock 165 __atomic_acquire( &data[iproc].lock ); 166 /*paranoid*/ verify(data[iproc].lock); 167 } 168 169 static inline void ready_schedule_unlock( struct cluster * cltr, struct processor * proc) with(cltr->ready_lock) { 170 unsigned iproc = proc->id; 171 /*paranoid*/ verify(data[iproc].handle == proc); 172 /*paranoid*/ verify(iproc < ready); 173 /*paranoid*/ verify(data[iproc].lock); 174 __atomic_unlock(&data[iproc].lock); 175 } 176 177 //----------------------------------------------------------------------- 178 // Writer side : acquire when changing the ready queue, e.g. adding more 179 // queues or removing them. 180 uint_fast32_t ready_mutate_lock( struct cluster & cltr ); 181 182 void ready_mutate_unlock( struct cluster & cltr, uint_fast32_t /* value returned by lock */ ); 183 184 //======================================================================= 185 // Ready-Queue API 186 //----------------------------------------------------------------------- 187 // push thread onto a ready queue for a cluster 188 // returns true if the list was previously empty, false otherwise 189 __attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd); 190 191 //----------------------------------------------------------------------- 192 // pop thread from the ready queue of a cluster 193 // returns 0p if empty 194 __attribute__((hot)) struct $thread * pop(struct cluster * cltr); 195 196 //----------------------------------------------------------------------- 197 // Increase the width of the ready queue (number of lanes) by 4 198 void ready_queue_grow (struct cluster * cltr); 199 200 //----------------------------------------------------------------------- 201 // Decrease the width of the ready queue (number of lanes) by 4 202 void ready_queue_shrink(struct cluster * cltr); 203 204 //----------------------------------------------------------------------- 205 // Statics call at the end of each thread to register statistics 206 #if !defined(__CFA_NO_STATISTICS__) 207 void stats_tls_tally(struct cluster * cltr); 208 #else 209 static inline void stats_tls_tally(struct cluster * cltr) {} 210 #endif 211 105 212 // Local Variables: // 106 213 // mode: c //
Note:
See TracChangeset
for help on using the changeset viewer.