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 | }
|
---|