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