[601bd9e] | 1 | // this is a code stub and will not compile |
---|
| 2 | |
---|
| 3 | // tries to atomically swap two queues and returns 0p if the swap failed |
---|
| 4 | // returns ptr to newly owned queue if swap succeeds |
---|
| 5 | static inline work_queue * try_swap_queues( worker & this, unsigned int victim_idx, unsigned int my_idx ) with(this) { |
---|
| 6 | work_queue * my_queue = request_queues[my_idx]; |
---|
| 7 | work_queue * other_queue = request_queues[victim_idx]; |
---|
| 8 | |
---|
| 9 | // if either queue is 0p then they are in the process of being stolen |
---|
| 10 | if ( other_queue == 0p || my_queue == 0p ) return 0p; |
---|
| 11 | |
---|
| 12 | // try to set our queue ptr to be 0p. If it fails someone moved our queue so return false |
---|
| 13 | if ( !__atomic_compare_exchange_n( &request_queues[my_idx], &my_queue, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) |
---|
| 14 | return 0p; |
---|
| 15 | |
---|
| 16 | // try to set other queue ptr to be our queue ptr. If it fails someone moved the other queue so fix up then return false |
---|
| 17 | if ( !__atomic_compare_exchange_n( &request_queues[victim_idx], &other_queue, my_queue, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) { |
---|
| 18 | /* paranoid */ verify( request_queues[my_idx] == 0p ); |
---|
| 19 | request_queues[my_idx] = my_queue; // reset my queue ptr back to appropriate val |
---|
| 20 | return 0p; |
---|
| 21 | } |
---|
| 22 | |
---|
| 23 | // we have successfully swapped and since our queue is 0p no one will touch it so write back new queue ptr non atomically |
---|
| 24 | request_queues[my_idx] = other_queue; // last write does not need to be atomic |
---|
| 25 | return other_queue; |
---|
| 26 | } |
---|
| 27 | |
---|
| 28 | // This routine is atomic |
---|
| 29 | bool CAS( work_queue ** ptr, work_queue ** old, work_queue * new ) { |
---|
| 30 | if ( *ptr != *old ) |
---|
| 31 | return false; |
---|
| 32 | *ptr = new; |
---|
| 33 | return true; |
---|
| 34 | } |
---|
| 35 | |
---|
| 36 | bool try_swap_queues( worker & this, uint victim_idx, uint my_idx ) with(this) { |
---|
| 37 | work_queue * my_queue = request_queues[my_idx]; |
---|
| 38 | work_queue * vic_queue = request_queues[victim_idx]; |
---|
| 39 | |
---|
| 40 | // If either queue is 0p then they are in the process of being stolen |
---|
| 41 | // 0p is CForAll's equivalent of C++'s nullptr |
---|
| 42 | if ( vic_queue == 0p || my_queue == 0p ) return false; |
---|
| 43 | |
---|
| 44 | // Try to set our queue ptr to be 0p. |
---|
| 45 | // If this CAS fails someone moved our queue so return false |
---|
| 46 | if ( !CAS( &request_queues[my_idx], &my_queue, 0p ) ) |
---|
| 47 | return false; |
---|
| 48 | |
---|
| 49 | // Try to set other queue ptr to be our queue ptr. |
---|
| 50 | // If it fails someone moved the other queue, so fix up then return false |
---|
| 51 | if ( !CAS( &request_queues[victim_idx], &vic_queue, my_queue ) ) { |
---|
| 52 | request_queues[my_idx] = my_queue; // reset queue ptr back to prev val |
---|
| 53 | return false; |
---|
| 54 | } |
---|
| 55 | |
---|
| 56 | // Successfully swapped. |
---|
| 57 | // Our queue is 0p so no one will touch it so write back without CAS is safe |
---|
| 58 | request_queues[my_idx] = vic_queue; |
---|
| 59 | return true; |
---|
| 60 | } |
---|