1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3  * See COPYRIGHT in top-level directory.
4  */
5 
6 #include <stdlib.h>
7 #include "lock/zm_tlp.h"
8 
9 /* The algorithm follows this logic
10 
11 acquire()
12 lock(high_p)
13 do {
14     if(CAS(common, FREE, GRANTED);
15         break;
16     if (CAS(common, GRANTED, REQUEST {
17         while(common != GRANTED) ;
18         break;
    }
19 } while (1)
20 unlock(high_p)
21 
22 CS
23 
24 release()
25 if(!CAS(common, REQUEST, GRANTED); //optimistic
26     common = FREE
27 
28 acquire_low()
29 lock(low_p)
30 do {
31     while(common != FREE) ;
32     if(CAS(common, FREE, GRANTED);
33         break;
34 } whil (1)
35 
36 
37 CS
38 
39 release_low()
40 if(!CAS(common, REQUEST, GRANTED); //optimistic
41     common = FREE;
42 unlock(low_p)
43 */
44 
45 /* Helper functions */
46 
47 #if (ZM_TLP_HIGH_P == ZM_TICKET)
48 #define zm_tlp_init_high_p(L) zm_ticket_init(&L->high_p)
49 #elif (ZM_TLP_HIGH_P == ZM_MCS)
50 #define zm_tlp_init_high_p(L) zm_mcs_init(&L->high_p)
51 #elif (ZM_TLP_HIGH_P == ZM_HMCS)
52 #define zm_tlp_init_high_p(L) zm_hmcs_init(&L->high_p)
53 #endif
54 
55 #if (ZM_TLP_HIGH_P == ZM_TICKET)
56 #define zm_tlp_destroy_high_p(L) zm_ticket_destroy(&L->high_p)
57 #elif (ZM_TLP_HIGH_P == ZM_MCS)
58 #define zm_tlp_destroy_high_p(L) zm_mcs_destroy(&L->high_p)
59 #elif (ZM_TLP_HIGH_P == ZM_HMCS)
60 #define zm_tlp_destroy_high_p(L) zm_hmcs_destroy(&L->high_p)
61 #endif
62 
63 #if (ZM_TLP_HIGH_P == ZM_TICKET)
64 #define zm_tlp_acquire_high_p(L)              zm_ticket_acquire(&L->high_p)
65 #define zm_tlp_acquire_high_pc(L, local_ctxt) zm_ticket_acquire(&L->high_p)
66 #elif (ZM_TLP_HIGH_P == ZM_MCS)
67 #define zm_tlp_acquire_high_p(L)              zm_mcs_acquire(L->high_p)
68 #define zm_tlp_acquire_high_pc(L, local_ctxt) zm_mcs_acquire_c(L->high_p, local_ctxt)
69 #elif (ZM_TLP_HIGH_P == ZM_HMCS)
70 #define zm_tlp_acquire_high_p(L)              zm_hmcs_acquire(L->high_p)
71 #define zm_tlp_acquire_high_pc(L, local_ctxt) zm_hmcs_acquire(L->high_p)
72 #endif
73 
74 #if (ZM_TLP_HIGH_P == ZM_TICKET)
75 #define zm_tlp_tryacq_high_p(L, s)               zm_ticket_tryacq(&L->high_p, s)
76 #define zm_tlp_tryacq_high_pc(L, local_ctxt, s)  zm_ticket_tryacq(&L->high_p, s)
77 #elif (ZM_TLP_HIGH_P == ZM_MCS)
78 #define zm_tlp_tryacq_high_p(L, s)               zm_mcs_tryacq(&L->high_p, local_ctxt, s)
79 #define zm_tlp_tryacq_high_pc(L, local_ctxt, s)  zm_mcs_tryacq(&L->high_p, local_ctxt, s)
80 #elif (ZM_TLP_HIGH_P == ZM_HMCS)
81 #define zm_tlp_tryacq_high_p(L, s)               zm_hmcs_tryacq(L->high_p, s)
82 #define zm_tlp_tryacq_high_pc(L, local_ctxt, s)  zm_hmcs_tryacq(L->high_p, s)
83 #endif
84 
85 #if (ZM_TLP_HIGH_P == ZM_TICKET)
86 #define zm_tlp_release_high_p(L)         zm_ticket_release(&L->high_p)
87 #define zm_tlp_release_high_pc(L, ctxt)  zm_ticket_release(&L->high_p)
88 #elif (ZM_TLP_HIGH_P == ZM_MCS)
89 #define zm_tlp_release_high_p(L)         zm_mcs_release(L->high_p);
90 #define zm_tlp_release_high_pc(L, ctxt)  zm_mcs_release_c(L->high_p, ctxt);
91 #elif (ZM_TLP_HIGH_P == ZM_HMCS)
92 #define zm_tlp_release_high_p(L)         zm_hmcs_release(L->high_p);
93 #define zm_tlp_release_high_pc(L, ctxt)  zm_hmcs_release(L->high_p);
94 #endif
95 
96 #if (ZM_TLP_LOW_P == ZM_TICKET)
97 #define zm_tlp_init_low_p(L) zm_ticket_init(&L->low_p)
98 #elif (ZM_TLP_LOW_P == ZM_MCS)
99 #define zm_tlp_init_low_p(L) zm_mcs_init(&L->low_p)
100 #elif (ZM_TLP_LOW_P == ZM_HMCS)
101 #define zm_tlp_init_low_p(L) zm_hmcs_init(&L->low_p)
102 #endif
103 
104 #if (ZM_TLP_LOW_P == ZM_TICKET)
105 #define zm_tlp_destroy_low_p(L) zm_ticket_destroy(&L->low_p)
106 #elif (ZM_TLP_LOW_P == ZM_MCS)
107 #define zm_tlp_destroy_low_p(L) zm_mcs_destroy(&L->low_p)
108 #elif (ZM_TLP_LOW_P == ZM_HMCS)
109 #define zm_tlp_destroy_low_p(L) zm_hmcs_destroy(&L->low_p)
110 #endif
111 
112 #if (ZM_TLP_LOW_P == ZM_TICKET)
113 #define zm_tlp_acquire_low_p(L)              zm_ticket_acquire(&L->low_p)
114 #define zm_tlp_acquire_low_pc(L, local_ctxt) zm_ticket_acquire(&L->low_p)
115 #elif (ZM_TLP_LOW_P == ZM_MCS)
116 #define zm_tlp_acquire_low_p(L)              zm_mcs_acquire(L->low_p)
117 #define zm_tlp_acquire_low_pc(L, local_ctxt) zm_mcs_acquire_c(L->low_p, local_ctxt)
118 #elif (ZM_TLP_LOW_P == ZM_HMCS)
119 #define zm_tlp_acquire_low_p(L)              zm_hmcs_acquire(L->low_p)
120 #define zm_tlp_acquire_low_pc(L, local_ctxt) zm_hmcs_acquire(L->low_p)
121 #endif
122 
123 #if (ZM_TLP_LOW_P == ZM_TICKET)
124 #define zm_tlp_tryacq_low_p(L, s)               zm_ticket_tryacq(&L->low_p, s)
125 #define zm_tlp_tryacq_low_pc(L, local_ctxt, s)  zm_ticket_tryacq(&L->low_p, s)
126 #elif (ZM_TLP_LOW_P == ZM_MCS)
127 #define zm_tlp_tryacq_low_p(L, s)               zm_mcs_tryacq(L->low_p, s)
128 #define zm_tlp_tryacq_low_pc(L, local_ctxt, s)  zm_mcs_tryacq(L->low_p, s)
129 #elif (ZM_TLP_LOW_P == ZM_HMCS)
130 #define zm_tlp_tryacq_low_p(L, s)               zm_hmcs_tryacq(L->low_p, s)
131 #define zm_tlp_tryacq_low_pc(L, local_ctxt, s)  zm_hmcs_tryacq(L->low_p, s)
132 #endif
133 
134 #if (ZM_TLP_LOW_P == ZM_TICKET)
135 #define zm_tlp_release_low_p(L)         zm_ticket_release(&L->low_p)
136 #define zm_tlp_release_low_pc(L, ctxt)  zm_ticket_release(&L->low_p)
137 #elif (ZM_TLP_LOW_P == ZM_MCS)
138 #define zm_tlp_release_low_p(L)         zm_mcs_release(L->low_p);
139 #define zm_tlp_release_low_pc(L, ctxt)  zm_mcs_release_c(L->low_p, ctxt);
140 #elif (ZM_TLP_LOW_P == ZM_HMCS)
141 #define zm_tlp_release_low_p(L)         zm_hmcs_release(L->low_p)
142 #define zm_tlp_release_low_pc(L, ctxt)  zm_hmcs_release(L->low_p)
143 #endif
144 
145 #if (ZM_TLP_HIGH_P == ZM_TICKET)
146 #define zm_tlp_nowaiters_high_p(L)        zm_ticket_nowaiters(&L->high_p)
147 #define zm_tlp_nowaiters_high_pc(L, ctxt) zm_ticket_nowaiters(&L->high_p)
148 #elif (ZM_TLP_HIGH_P == ZM_MCS)
149 #define zm_tlp_nowaiters_high_p(L)        zm_mcs_nowaiters(L->high_p)
150 #define zm_tlp_nowaiters_high_pc(L, ctxt) zm_mcs_nowaiters_c(L->high_p, ctxt)
151 #elif (ZM_TLP_HIGH_P == ZM_HMCS)
152 #define zm_tlp_nowaiters_high_p(L)        zm_hmcs_nowaiters(L->high_p)
153 #define zm_tlp_nowaiters_high_pc(L, ctxt) zm_hmcs_nowaiters(L->high_p)
154 #endif
155 
zm_tlp_init(zm_tlp_t * L)156 int zm_tlp_init(zm_tlp_t *L)
157 {
158    zm_tlp_init_high_p(L);
159    L->go_straight = 0;
160    L->low_p_acq = 0;
161    zm_ticket_init(&L->filter);
162    zm_tlp_init_low_p(L);
163    return 0;
164 }
165 
zm_tlp_destroy(zm_tlp_t * L)166 int zm_tlp_destroy(zm_tlp_t *L)
167 {
168    zm_tlp_destroy_high_p(L);
169    zm_ticket_destroy(&L->filter);
170    zm_tlp_destroy_low_p(L);
171    return 0;
172 }
173 
zm_tlp_acquire(zm_tlp_t * L)174 int zm_tlp_acquire(zm_tlp_t *L) {
175     /* Acquire the high priority lock */
176    zm_tlp_acquire_high_p(L);
177    if (!L->go_straight) {
178        zm_ticket_acquire(&L->filter);
179        L->go_straight = 1;
180    }
181     return 0;
182 }
183 
zm_tlp_tryacq(zm_tlp_t * L,int * success)184 int zm_tlp_tryacq(zm_tlp_t *L, int *success) {
185     int acquired = 0;
186     zm_tlp_tryacq_high_p(L, &acquired);
187     if(acquired) {
188         if (!L->go_straight) {
189             zm_ticket_tryacq(&L->filter, &acquired);
190             if (acquired)
191                 L->go_straight = 1;
192         }
193     }
194     return 0;
195 }
196 
zm_tlp_acquire_low(zm_tlp_t * L)197 int zm_tlp_acquire_low(zm_tlp_t *L) {
198     /* Acquire the low priority lock */
199    zm_tlp_acquire_low_p(L);
200    zm_ticket_acquire(&L->filter);
201    L->low_p_acq = 1;
202     return 0;
203 }
204 
zm_tlp_tryacq_low(zm_tlp_t * L,int * success)205 int zm_tlp_tryacq_low(zm_tlp_t *L, int *success) {
206     int acquired = 0;
207     zm_tlp_tryacq_low_p(L, &acquired);
208     if(acquired) {
209         if (!L->go_straight) {
210             zm_ticket_tryacq(&L->filter, &acquired);
211             if (acquired)
212                 L->go_straight = 1;
213         }
214     }
215     return 0;
216 }
217 
218 /* Release the lock */
zm_tlp_release(zm_tlp_t * L)219 int zm_tlp_release(zm_tlp_t *L) {
220    if (!L->low_p_acq) {
221        if (zm_tlp_nowaiters_high_p(L)) {
222            L->go_straight = 0;
223            zm_ticket_release(&L->filter);
224        }
225        zm_tlp_release_high_p(L);
226    } else {
227        L->low_p_acq = 0;
228        zm_ticket_release(&L->filter);
229        zm_tlp_release_low_p(L);
230    }
231     return 0;
232 }
233 
zm_tlp_acquire_c(zm_tlp_t * L,zm_mcs_qnode_t * local_ctxt)234 int zm_tlp_acquire_c(zm_tlp_t *L, zm_mcs_qnode_t *local_ctxt) {
235     /* Acquire the high priority lock */
236    zm_tlp_acquire_high_pc(L, local_ctxt);
237    if (!L->go_straight) {
238        zm_ticket_acquire(&L->filter);
239        L->go_straight = 1;
240    }
241     return 0;
242 }
243 
zm_tlp_acquire_low_c(zm_tlp_t * L,zm_mcs_qnode_t * local_ctxt)244 int zm_tlp_acquire_low_c(zm_tlp_t *L, zm_mcs_qnode_t *local_ctxt) {
245     /* Acquire the low priority lock */
246    zm_tlp_acquire_low_pc(L, local_ctxt);
247    zm_ticket_acquire(&L->filter);
248    L->low_p_acq = 1;
249     return 0;
250 }
251 
252 /* Release the lock */
zm_tlp_release_c(zm_tlp_t * L,zm_mcs_qnode_t * ctxt)253 int zm_tlp_release_c(zm_tlp_t *L, zm_mcs_qnode_t* ctxt) {
254    if (!L->low_p_acq) {
255        if (zm_tlp_nowaiters_high_pc(L, ctxt)) {
256            L->go_straight = 0;
257            zm_ticket_release(&L->filter);
258        }
259        zm_tlp_release_high_pc(L, ctxt);
260    } else {
261        L->low_p_acq = 0;
262        zm_ticket_release(&L->filter);
263        zm_tlp_release_low_pc(L, ctxt);
264    }
265     return 0;
266 }
267