1 /* $Id: lock.c,v 1.4 2003/09/09 22:14:58 poettering Exp $
2  *
3  * This file is part of libshbuf.
4  *
5  * libshbuf is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * libshbuf is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13  * for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with libshbuf; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
18  */
19 
20 #include <assert.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 #include "shbuf.h"
25 #include "internal.h"
26 #include "thread.h"
27 #include "shbuferr.h"
28 
29 #ifndef MIN
30 #define MIN(a,b) ((a) > (b) ? (b) : (a))
31 #endif
32 
shbuf_status_lock(shbuf * sb)33 int shbuf_status_lock(shbuf* sb) {
34     int r;
35     struct sembuf buf;
36 
37     assert(sb);
38 
39     buf.sem_num = 0;
40     buf.sem_op = -1;
41     buf.sem_flg = 0;
42 
43     if ((r = semop(sb->semid, &buf, 1)) != 0) {
44         shbuf_set_errno(SHBUF_LOCKFAILED);
45         return -1;
46     }
47 
48     return 0;
49 }
50 
shbuf_status_unlock(shbuf * sb)51 int shbuf_status_unlock(shbuf* sb) {
52     struct sembuf buf;
53     int r;
54 
55     assert(sb);
56 
57     buf.sem_num = 0;
58     buf.sem_op = 1;
59     buf.sem_flg = 0;
60 
61     if ((r = semop(sb->semid, &buf, 1)) != 0) {
62         shbuf_set_errno(SHBUF_UNLOCKFAILED);
63         return -1;
64     }
65 
66     return 0;
67 }
68 
shbuf_reset(shbuf * sb)69 int shbuf_reset(shbuf* sb) {
70     assert(sb);
71 
72     if (shbuf_status_lock(sb) < 0)
73         return -1;
74 
75     sb->control->status.read_idx = sb->control->status.length = 0;
76     sb->control->status.ignore_read_inc = sb->control->status.ignore_write_inc = 1;
77     sb->control->status.backlog = 0;
78 
79     if (shbuf_status_unlock(sb) < 0)
80         return -1;
81 
82     return 0;
83 }
84 
shbuf_zero(shbuf * sb)85 int shbuf_zero(shbuf* sb) {
86     assert(sb);
87 
88     if (shbuf_status_lock(sb) < 0)
89         return -1;
90 
91     sb->control->status.read_idx = sb->control->status.length = 0;
92     sb->control->status.ignore_read_inc = sb->control->status.ignore_write_inc = 1;
93     sb->control->status.backlog = 0;
94 
95     memset(sb->buffer, 0, sb->control->size);
96 
97     if (shbuf_status_unlock(sb) < 0)
98         return -1;
99 
100     return 0;
101 }
102 
shbuf_get_read_pointer(shbuf * sb,unsigned long * l)103 const unsigned char* shbuf_get_read_pointer(shbuf *sb, unsigned long *l) {
104     const unsigned char *p;
105     assert(sb && l);
106 
107     if (shbuf_status_lock(sb) < 0)
108         return (const unsigned char*) -1;
109 
110     if (sb->control->status.length) {
111         *l = MIN(sb->control->status.length,
112                  sb->control->size - sb->control->status.read_idx);
113         p = (const unsigned char*) (sb->buffer + sb->control->status.read_idx);
114     } else {
115         *l = 0;
116         p = NULL;
117     }
118 
119     sb->control->status.ignore_read_inc = 0;
120 
121     if (shbuf_status_unlock(sb) < 0)
122         return (const unsigned char*) -1;
123 
124     return p;
125 }
126 
shbuf_inc_read_pointer(shbuf * sb,unsigned long r)127 int shbuf_inc_read_pointer(shbuf *sb, unsigned long r) {
128     assert(sb && r);
129 
130     if (shbuf_status_lock(sb) < 0)
131         return -1;
132 
133     if (!sb->control->status.ignore_read_inc) {
134 
135         if (r > sb->control->status.length)
136             r = sb->control->status.length;
137 
138         sb->control->status.length -= r;
139         sb->control->status.read_idx += r;
140         sb->control->status.read_idx %= sb->control->size;
141         sb->control->status.read_count+= r;
142         sb->control->status.backlog += r;
143 
144         if (sb->control->status.backlog > sb->control->status.backlog_target)
145             sb->control->status.backlog = sb->control->status.backlog_target;
146     }
147 
148     if (shbuf_status_unlock(sb) < 0)
149         return -1;
150 
151     return 0;
152 }
153 
154 
shbuf_get_write_pointer(shbuf * sb,unsigned long * l)155 unsigned char* shbuf_get_write_pointer(shbuf *sb, unsigned long *l) {
156     unsigned char *p;
157     assert(sb && l);
158 
159     if (shbuf_status_lock(sb) < 0)
160         return (unsigned char*) -1;
161 
162     if (sb->control->status.length + sb->control->status.backlog < sb->control->size) {
163         unsigned long write_idx = sb->control->status.read_idx + sb->control->status.length;
164 
165         write_idx %= sb->control->size;
166 
167         *l = MIN(sb->control->size - sb->control->status.length - sb->control->status.backlog,
168                  sb->control->size - write_idx);
169 
170         p = sb->buffer + write_idx;
171     } else {
172         *l = 0;
173         p = NULL;
174     }
175 
176     sb->control->status.ignore_write_inc = 0;
177 
178     if (shbuf_status_unlock(sb) < 0)
179         return (unsigned char*) -1;
180 
181     return p;
182 }
183 
184 
shbuf_inc_write_pointer(shbuf * sb,unsigned long r)185 int shbuf_inc_write_pointer(shbuf *sb, unsigned long r) {
186     assert(sb && r);
187 
188     if (shbuf_status_lock(sb) < 0)
189         return -1;
190 
191     if (!sb->control->status.ignore_write_inc) {
192         unsigned long foo = sb->control->size - sb->control->status.length;
193 
194         if (r > foo)
195             r = foo;
196 
197         sb->control->status.length += r;
198         sb->control->status.write_count+= r;
199 
200         if (sb->control->status.length + sb->control->status.backlog > sb->control->size)
201             sb->control->status.backlog = sb->control->size - sb->control->status.length;
202     }
203 
204     if (shbuf_status_unlock(sb) < 0)
205         return -1;
206 
207     return 0;
208 }
209 
210 
shbuf_connected(shbuf * sb)211 int shbuf_connected(shbuf *sb) {
212     int r;
213     assert(sb);
214 
215     if (sb->is_dead)
216         return 0;
217 
218     if (shbuf_status_lock(sb) < 0)
219         return -1;
220 
221     r = sb->control->client_attached && sb->control->provider_attached;
222 
223     if (shbuf_status_unlock(sb) < 0)
224         return -1;
225 
226     return r;
227 
228 }
229 
shbuf_notify_enable(shbuf * sb,int b)230 int shbuf_notify_enable(shbuf* sb, int b) {
231     assert(sb);
232 
233     if (shbuf_status_lock(sb) < 0)
234         return -1;
235 
236     if (sb->is_provider)
237         sb->control->provider_notify = b ? 1 : 0;
238     else
239         sb->control->client_notify = b ? 1 : 0;
240 
241     if (shbuf_status_unlock(sb) < 0)
242         return -1;
243 
244     if (b)
245         return thread_start(sb);
246     else
247         thread_stop(sb);
248 
249     return 0;
250 }
251 
shbuf_is_empty(shbuf * sb)252 int shbuf_is_empty(shbuf *sb) {
253     unsigned long r;
254     assert(sb);
255 
256     if (shbuf_status_lock(sb) < 0)
257         return -1;
258 
259     r = sb->control->status.length;
260 
261     if (shbuf_status_unlock(sb) < 0)
262         return -1;
263 
264     return !r;
265 }
266 
shbuf_is_full(shbuf * sb)267 int shbuf_is_full(shbuf *sb) {
268     unsigned long r;
269     assert(sb);
270 
271     if (shbuf_status_lock(sb) < 0)
272         return -1;
273 
274     r = sb->control->size - sb->control->status.length - sb->control->status.backlog;
275 
276     if (shbuf_status_unlock(sb) < 0)
277         return -1;
278 
279     return !r;
280 }
281 
shbuf_rewind(shbuf * sb,unsigned long v)282 unsigned long shbuf_rewind(shbuf *sb, unsigned long v) {
283     unsigned long r;
284 
285     if (shbuf_status_lock(sb) < 0)
286         return (unsigned long) -1;
287 
288     if (v == 0)
289         r = sb->control->status.backlog;
290     else {
291         r = MIN(v, sb->control->status.backlog);
292 
293         sb->control->status.backlog -= r;
294         sb->control->status.length += r;
295 
296         if (sb->control->status.read_idx < r) {
297             sb->control->status.read_idx = sb->control->size;
298             r -= sb->control->status.read_idx;
299         }
300         sb->control->status.read_idx -= r;
301     }
302 
303     if (shbuf_status_unlock(sb) < 0)
304         return (unsigned long) -1;
305 
306     return r;
307 }
308 
shbuf_write(shbuf * sb,const unsigned char * c,signed long l)309 signed long shbuf_write(shbuf *sb, const unsigned char*c, signed long l) {
310     unsigned long _l;
311     unsigned char *_c;
312 
313     assert(sb && c && l > 0);
314 
315     do {
316         if ((_c = shbuf_get_write_pointer(sb, &_l)) == (unsigned char*) -1)
317             return -1;
318 
319         if (shbuf_wait(sb) < 0)
320             return -1;
321     } while (!_c);
322 
323     _l = MIN(l, _l);
324 
325     memcpy(_c, c, _l);
326 
327     return shbuf_inc_write_pointer(sb, _l);
328 }
329 
shbuf_read(shbuf * sb,unsigned char * c,signed long l)330 signed long shbuf_read(shbuf *sb, unsigned char*c, signed long l) {
331     unsigned long _l;
332     const unsigned char *_c;
333 
334     assert(sb && c && l > 0);
335 
336     do {
337         if ((_c = shbuf_get_read_pointer(sb, &_l)) == (unsigned char*) -1)
338             return -1;
339 
340         if (shbuf_wait(sb) != 0)
341             return -1;
342     } while (!_c);
343 
344     _l = MIN(l, _l);
345 
346     memcpy(c, _c, _l);
347 
348     return shbuf_inc_read_pointer(sb, _l);
349 }
350 
351 
shbuf_set_backlog_target(shbuf * sb,unsigned long bl)352 int shbuf_set_backlog_target(shbuf *sb, unsigned long bl) {
353     if (shbuf_status_lock(sb) < 0)
354         return -1;
355 
356     if (bl < sb->control->size)
357         sb->control->status.backlog_target = bl;
358     else
359         sb->control->status.backlog_target = sb->control->size -1;
360 
361 
362     if (shbuf_status_unlock(sb) < 0)
363         return -1;
364 
365     return 0;
366 }
367 
shbuf_get_backlog_target(shbuf * sb)368 unsigned long shbuf_get_backlog_target(shbuf *sb) {
369     unsigned long r;
370 
371     if (shbuf_status_lock(sb) < 0)
372         return (unsigned long) -1;
373 
374     r = sb->control->status.backlog_target;
375 
376     if (shbuf_status_unlock(sb) < 0)
377         return -1;
378 
379     return r;
380 }
381