Syncs up Makeconfig and the Makelocal.template
[akaros.git] / user / parlib / mcs.c
1 #include <vcore.h>
2 #include <mcs.h>
3 #include <arch/atomic.h>
4 #include <string.h>
5 #include <stdlib.h>
6
7 // MCS locks
8 void mcs_lock_init(mcs_lock_t* lock)
9 {
10         memset(lock,0,sizeof(mcs_lock_t));
11 }
12
13 static inline mcs_lock_qnode_t* mcs_qnode_swap(mcs_lock_qnode_t** addr, mcs_lock_qnode_t* val)
14 {
15         return (mcs_lock_qnode_t*)atomic_swap((int*)addr,(int)val);
16 }
17
18 void mcs_lock_lock(mcs_lock_t* lock)
19 {
20         mcs_lock_qnode_t* qnode = &lock->qnode[vcore_id()];
21         qnode->next = 0;
22         mcs_lock_qnode_t* predecessor = mcs_qnode_swap(&lock->lock,qnode);
23         if(predecessor)
24         {
25                 qnode->locked = 1;
26                 predecessor->next = qnode;
27                 while(qnode->locked);
28         }
29 }
30
31 void mcs_lock_unlock(mcs_lock_t* lock)
32 {
33         mcs_lock_qnode_t* qnode = &lock->qnode[vcore_id()];
34         if(qnode->next == 0)
35         {
36                 mcs_lock_qnode_t* old_tail = mcs_qnode_swap(&lock->lock,0);
37                 if(old_tail == qnode)
38                         return;
39
40                 mcs_lock_qnode_t* usurper = mcs_qnode_swap(&lock->lock,old_tail);
41                 while(qnode->next == 0);
42                 if(usurper)
43                         usurper->next = qnode->next;
44                 else
45                         qnode->next->locked = 0;
46         }
47         else
48                 qnode->next->locked = 0;
49 }
50
51 // MCS dissemination barrier!
52 int mcs_barrier_init(mcs_barrier_t* b, size_t np)
53 {
54         if(np > max_vcores())
55                 return -1;
56         b->allnodes = (mcs_dissem_flags_t*)malloc(np*sizeof(mcs_dissem_flags_t));
57         memset(b->allnodes,0,np*sizeof(mcs_dissem_flags_t));
58         b->nprocs = np;
59
60         b->logp = (np & (np-1)) != 0;
61         while(np >>= 1)
62                 b->logp++;
63
64         size_t i,k;
65         for(i = 0; i < b->nprocs; i++)
66         {
67                 b->allnodes[i].parity = 0;
68                 b->allnodes[i].sense = 1;
69
70                 for(k = 0; k < b->logp; k++)
71                 {
72                         size_t j = (i+(1<<k)) % b->nprocs;
73                         b->allnodes[i].partnerflags[0][k] = &b->allnodes[j].myflags[0][k];
74                         b->allnodes[i].partnerflags[1][k] = &b->allnodes[j].myflags[1][k];
75                 } 
76         }
77
78         return 0;
79 }
80
81 void mcs_barrier_wait(mcs_barrier_t* b, size_t pid)
82 {
83         mcs_dissem_flags_t* localflags = &b->allnodes[pid];
84         size_t i;
85         for(i = 0; i < b->logp; i++)
86         {
87                 *localflags->partnerflags[localflags->parity][i] = localflags->sense;
88                 while(localflags->myflags[localflags->parity][i] != localflags->sense);
89         }
90         if(localflags->parity)
91                 localflags->sense = 1-localflags->sense;
92         localflags->parity = 1-localflags->parity;
93 }
94