Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 : : /*
3 : : * Generic Partial Lock
4 : : * see https://github.com/greensky00/partiallock
5 : : */
6 : :
7 : : #include <stdio.h>
8 : : #include <stdlib.h>
9 : : #include <string.h>
10 : :
11 : : #include "partiallock.h"
12 : :
13 : : struct plock_node {
14 : : void *lock;
15 : : void *start;
16 : : void *len;
17 : : volatile uint32_t wcount; // waiting count
18 : : struct list_elem le;
19 : : };
20 : :
21 : 248 : int plock_init(struct plock *plock, struct plock_config *config)
22 : : {
23 [ + - ][ - + ]: 248 : if (!plock || !config) {
24 : 0 : return PLOCK_RESULT_INVALID_ARGS;
25 : : }
26 : :
27 : 248 : plock->ops = (struct plock_ops *)malloc(sizeof(struct plock_ops));
28 [ - + ]: 248 : if (!plock->ops) {
29 : 0 : return PLOCK_RESULT_ALLOC_FAIL;
30 : : }
31 : 248 : *plock->ops = *(config->ops);
32 : :
33 : : // allocate and init lock
34 : 248 : plock->sizeof_lock_user = config->sizeof_lock_user;
35 : 248 : plock->sizeof_lock_internal = config->sizeof_lock_internal;
36 : 248 : plock->sizeof_range = config->sizeof_range;
37 : 248 : plock->aux = config->aux;
38 : 248 : plock->lock = (void *)malloc(plock->sizeof_lock_internal);
39 : 248 : plock->ops->init_internal(plock->lock);
40 : :
41 : : // init list and tree
42 : 248 : list_init(&plock->active);
43 : 248 : list_init(&plock->inactive);
44 : :
45 : 248 : return PLOCK_RESULT_SUCCESS;
46 : : }
47 : :
48 : 7685349 : plock_entry_t *plock_lock(struct plock *plock, void *start, void *len)
49 : : {
50 : 7685349 : struct list_elem *le = NULL;
51 : 7685349 : struct plock_node *node = NULL;
52 : :
53 [ + + ][ + - ]: 7685349 : if (!plock || !start || !len) {
[ - + ]
54 : 0 : return NULL;
55 : : }
56 : :
57 : : // grab plock's lock
58 : 7685349 : plock->ops->lock_internal(plock->lock);
59 : :
60 : : // find existing overlapped lock
61 : 7685490 : le = list_begin(&plock->active);
62 [ + + ]: 11949413 : while (le) {
63 : 4263923 : node = _get_entry(le, struct plock_node, le);
64 [ - + ]: 4263923 : if (plock->ops->is_overlapped(node->start, node->len,
65 : 4263923 : start, len, plock->aux)) {
66 : : // overlapped
67 : : // increase waiting count
68 : 0 : node->wcount++;
69 : : // release plock's lock
70 : 0 : plock->ops->unlock_internal(plock->lock);
71 : :
72 : : // grab node's lock
73 : 0 : plock->ops->lock_user(node->lock);
74 : : // got control .. that means the owner released the lock
75 : : // grab plock's lock
76 : 0 : plock->ops->lock_internal(plock->lock);
77 : : // decrease waiting count
78 : 0 : le = list_next(&node->le);
79 : 0 : node->wcount--;
80 [ # # ]: 0 : if (node->wcount == 0) {
81 : : // no other thread refers this node
82 : : // move from active to inactive
83 : 0 : list_remove(&plock->active, &node->le);
84 : 0 : list_push_front(&plock->inactive, &node->le);
85 : : }
86 : : // release node's lock
87 : 0 : plock->ops->unlock_user(node->lock);
88 : : } else {
89 : 4263923 : le = list_next(le);
90 : : }
91 : : }
92 : :
93 : : // get a free lock
94 : 7685490 : le = list_pop_front(&plock->inactive);
95 [ + + ]: 7685490 : if (le == NULL) {
96 : : // no free lock .. create one
97 : 103 : node = (struct plock_node *)malloc(sizeof(struct plock_node));
98 [ - + ]: 103 : if (!node) {
99 : 0 : plock->ops->unlock_internal(plock->lock);
100 : 0 : return NULL;
101 : : }
102 : 103 : node->lock = (void *)malloc(plock->sizeof_lock_user);
103 : 103 : plock->ops->init_user(node->lock);
104 : 103 : node->start = (void *)malloc(plock->sizeof_range);
105 : 103 : node->len = (void *)malloc(plock->sizeof_range);
106 [ + - ][ + - ]: 103 : if (!node->lock || !node->start || !node->len) {
[ - + ]
107 : 0 : free(node);
108 : 0 : plock->ops->unlock_internal(plock->lock);
109 : 0 : return NULL;
110 : : }
111 : : } else {
112 : 7685387 : node = _get_entry(le, struct plock_node ,le);
113 : : }
114 : 7685490 : node->wcount = 0;
115 : :
116 : : // copy start & len value
117 : 7685490 : memcpy(node->start, start, plock->sizeof_range);
118 : 7685490 : memcpy(node->len, len, plock->sizeof_range);
119 : : // insert into active list
120 : 7685490 : list_push_back(&plock->active, &node->le);
121 : :
122 : : // grab node's lock & release plock's lock
123 : 7685490 : plock->ops->lock_user(node->lock);
124 : 7685490 : plock->ops->unlock_internal(plock->lock);
125 : :
126 : 7685490 : return node;
127 : : }
128 : :
129 : 7680051 : int plock_unlock(struct plock *plock, plock_entry_t *plock_entry)
130 : : {
131 : 7680051 : struct plock_node *node = plock_entry;
132 : :
133 [ + + ][ - + ]: 7680051 : if (!plock || !plock_entry) {
134 : 0 : return PLOCK_RESULT_INVALID_ARGS;
135 : : }
136 : :
137 : : // grab plock's lock
138 : 7680051 : plock->ops->lock_internal(plock->lock);
139 : :
140 [ + - ]: 7685490 : if (node->wcount == 0) {
141 : : // no other thread refers this node
142 : : // move from active to inactive
143 : 7685490 : list_remove(&plock->active, &node->le);
144 : 7685490 : list_push_front(&plock->inactive, &node->le);
145 : : }
146 : 7685490 : plock->ops->unlock_user(node->lock);
147 : :
148 : : // release plock's lock
149 : 7685490 : plock->ops->unlock_internal(plock->lock);
150 : :
151 : 7684224 : return PLOCK_RESULT_SUCCESS;
152 : : }
153 : :
154 : 247 : int plock_destroy(struct plock *plock)
155 : : {
156 : : struct list_elem *le;
157 : : struct plock_node *node;
158 : :
159 [ - + ]: 247 : if (!plock) {
160 : 0 : return PLOCK_RESULT_INVALID_ARGS;
161 : : }
162 : :
163 : 247 : plock->ops->destroy_internal(plock->lock);
164 : :
165 : : // free all active locks
166 : 247 : le = list_begin(&plock->active);
167 [ - + ]: 247 : while(le) {
168 : 0 : node = _get_entry(le, struct plock_node, le);
169 : 0 : le = list_next(le);
170 : :
171 : : // unlock and destroy
172 : 0 : plock->ops->unlock_user(node->lock);
173 : 0 : plock->ops->destroy_user(node->lock);
174 : 0 : free(node->start);
175 : 0 : free(node->len);
176 : 0 : free(node->lock);
177 : 0 : free(node);
178 : : }
179 : :
180 : : // free all inactive locks
181 : 247 : le = list_begin(&plock->inactive);
182 [ + + ]: 350 : while(le) {
183 : 103 : node = _get_entry(le, struct plock_node, le);
184 : 103 : le = list_next(le);
185 : :
186 : : // destroy
187 : 103 : plock->ops->destroy_user(node->lock);
188 : 103 : free(node->start);
189 : 103 : free(node->len);
190 : 103 : free(node->lock);
191 : 103 : free(node);
192 : : }
193 : :
194 : : // free plock
195 : 247 : free(plock->lock);
196 : 247 : free(plock->ops);
197 : :
198 : 247 : return PLOCK_RESULT_SUCCESS;
199 : : }
200 : :
|