"Fossies" - the Fresh Open Source Software Archive 
Member "FunctionCheck-3.2.0/src/share/fc_fifo.c" (26 May 2012, 13019 Bytes) of package /linux/privat/old/FunctionCheck-3.2.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * FunctionCheck profiler
3 * (C) Copyright 2000-2012 Yannick Perret
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 /* fc_fifo: manage IPC buffer
21 */
22
23 /** general includes */
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/ipc.h>
27 #include <sys/shm.h>
28 #include <string.h>
29 #include <signal.h>
30 #include <sys/types.h>
31 #include <sys/time.h>
32 #include <unistd.h>
33 #include <errno.h>
34
35 /** personnal includes **/
36 #include "fc_fifo.h"
37 #include "fc_semaphore.h"
38 #include "fc_tools.h"
39
40 /** For FC_INIT and FC_LDYN added into FC_FIFO structure. */
41 /** Both are big-sized structures so they are not passed in
42 * fifo communication buffer, which has fixed-size elements,
43 * but embedded directly into the FC_FIFO control. */
44 #include "fc_com.h"
45
46 /** access for users **/
47 #define FC_USER_ALL ((1<<6)&(1<<7)&(1<<8))
48 #define FC_GROUP_ALL ((1<<3)&(1<<4)&(1<<5))
49 #define FC_OTHER_ALL ((1<<0)&(1<<1)&(1<<2))
50 #define FC_ALL_ALL (FC_USER_ALL&FC_GROUP_ALL&FC_OTHER_ALL)
51
52 #define MAX_LDYN 256
53
54 #define ACQUIRE_LOCK() { if (!fifo->singleMode) \
55 { \
56 fc_semaphore_get((FC_Semaphore volatile*)(&(fifo->sem)), pid); \
57 } \
58 }
59
60 #define RELEASE_LOCK() { if (!fifo->singleMode) \
61 { \
62 fc_semaphore_put((FC_Semaphore volatile*)(&(fifo->sem)), pid); \
63 } \
64 }
65
66 #define SLEEP() { \
67 struct timeval tv; \
68 tv.tv_sec = 0; \
69 tv.tv_usec = 10000; \
70 select(0, NULL, NULL, NULL, &tv); \
71 }
72
73 typedef struct
74 {
75 FC_INIT init;
76 FC_LDYN ldyn[MAX_LDYN];
77 FC_LDYN *lastLdynPtr; // pointer to last ldyn[] structure read
78 unsigned int numEntry; // number of entries in data
79 unsigned int entrySize; // size of each entry in data
80 unsigned int numData; // number of available data
81 unsigned int readIdx; // index in data
82 unsigned int writeIdx; // index in data
83 unsigned int singleMode;
84 unsigned int refCount; // reference count
85 FC_Semaphore sem;
86 unsigned char data[0]; // size is numEntry * entrySize
87 } _fifo_control;
88
89 /* create a shared memory buffer */
90 static int fc_fifo_create_buffer(unsigned int size)
91 {
92 int ret;
93
94 /* try to get a shared memory buffer with the given size */
95 ret = shmget(IPC_PRIVATE, size, 0777);
96
97 /* cannot process */
98 if (ret < 0)
99 {
100 fc_message("cannot create shared buffer with size '%d'", size);
101 fc_message("error returned: %s", strerror(errno));
102 return (ret);
103 }
104
105 /* ok */
106 fc_debug("shared buffer of size '%d' created (id=%d)", size, ret);
107 return (ret);
108 }
109
110 /* connect to an existing FIFO. returns the FIFO or FC_FIFO_NDEF.
111 the 'id' is the ID given by 'fc_fifo_create' */
112 FC_FIFO fc_fifo_connect(unsigned int id)
113 {
114 void *ret;
115
116 /* invalid argument */
117 if ((int) id < 0)
118 {
119 fc_message("invalid shared buffer Id (%d)", id);
120 return (NULL);
121 }
122
123 /* try to attach the buffer */
124 ret = shmat(id, NULL, 0700);
125 if ((ret == NULL) || (ret == (void*) - 1))
126 {/* cannot process */
127 fc_message("cannot attach shared buffer '%d'", id);
128 fc_message("error returned: %s", strerror(errno));
129 return (NULL);
130 }
131
132 /* ok */
133 fc_debug("shared buffer '%d' mapped at %p", id, ret);
134
135 /* reference ourself as client */
136 ((_fifo_control*)ret)->refCount++;
137
138 return (ret);
139 }
140
141 /* create a new FIFO. returns the FIFO or 'FC_FIFO_NDEF' on error
142 'esize' is the size of each element in the buffer, and 'id' is set to
143 the ID of the shared buffer, for connections. 'single' is TRUE
144 if the FIFO will be used with only one writer, and FALSE if
145 many writers can access the FIFO (with fc_fifo_write_single) */
146 FC_FIFO fc_fifo_create(unsigned int elements, unsigned int esize, unsigned int *id, unsigned int single)
147 {
148 int ret;
149 FC_FIFO mem;
150
151 if (elements <= 4)
152 {
153 /* default size */
154 elements = 32 * 1024;
155 }
156
157 /* get a shared buffer */
158 ret = fc_fifo_create_buffer(elements * esize + sizeof (_fifo_control));
159 *id = ret;
160 /* error */
161 if (ret < 0)
162 {
163 return (NULL);
164 }
165
166 /* attach the buffer */
167 mem = fc_fifo_connect(ret);
168 /* error */
169 if (mem == NULL)
170 {
171 return (NULL);
172 }
173
174 memset(&((_fifo_control*)mem)->init, 0, sizeof(((_fifo_control*)mem)->init));
175 memset(&((_fifo_control*)mem)->ldyn, 0, sizeof(((_fifo_control*)mem)->ldyn));
176
177 /* initialize the control part of the buffer */
178 ((_fifo_control*) mem)->numEntry = elements;
179 ((_fifo_control*) mem)->entrySize = esize;
180 ((_fifo_control*) mem)->numData = 0;
181 ((_fifo_control*) mem)->readIdx = 0;
182 ((_fifo_control*) mem)->writeIdx = 0;
183 ((_fifo_control*) mem)->singleMode = single;
184 ((_fifo_control*)mem)->refCount = 1;
185 fc_semaphore_init(&(((_fifo_control*) mem)->sem));
186
187 /* ok */
188 return (mem);
189 }
190
191 /* deconnect the given FIFO. once done, no more access to the FIFO
192 is possible.
193 delete flag if shm has no more reference. */
194 int fc_fifo_close(FC_FIFO buffer, unsigned int shmid, unsigned int delete)
195 {
196 unsigned int ref;
197 volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
198
199 ref = fifo->refCount;
200 if (ref == 0)
201 {
202 fc_message("Closing fifo with reference count of 0! (must be 1 minimum).\n");
203 }
204 else
205 {
206 /* remove our reference */
207 ref = --fifo->refCount;
208 }
209
210 /* detach the buffer */
211 shmdt((const void*)fifo);
212
213 /* delete shared memory */
214 if (delete && ref == 0)
215 shmctl(shmid, IPC_RMID, NULL);
216
217 return (1);
218 }
219
220 /* Return direct pointer to data instead of copying to user buffer.
221 Returns FALSE if EOF is reached before the end of the read.
222 No lock is being acquired when modifying FIFO state.
223 This function is not thread-safe. */
224 void* fc_fifo_read_single(FC_FIFO buffer, unsigned int size, unsigned int pid)
225 {
226 volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
227
228 /* check buffer size */
229 if (size > fifo->entrySize)
230 {
231 fc_message("read %d bytes from buffer is greater than FIFO element size (%d bytes).\n", size, fifo->entrySize);
232 return (0);
233 }
234
235 for(;;)
236 {
237 ACQUIRE_LOCK();
238
239 /* check if data is available for reading */
240 if ( fifo->numData == 0 )
241 {
242 /* alone already */
243 if (fifo->refCount <= 1)
244 {
245 // There is a race condition in the check above: fifo->numData == 0.
246 // Since the read and compare to zero operation is not atomic,
247 // it is possible after we read the value and during compare,
248 // then fc_fifo_write_single_done() increment it (e.g., write data to fifo)
249 // then process writing to fifo exit causing refCount to be 1.
250 // Here we do a second check to make sure there is really no more data left.
251
252 SLEEP();
253
254 if (fifo->numData > 0)
255 {
256 break;
257 }
258
259 // Really no more data,
260 // return NULL.
261 RELEASE_LOCK();
262 return 0;
263 }
264
265 RELEASE_LOCK();
266
267 SLEEP();
268 }
269 else
270 {
271 break;
272 }
273 }
274
275 return (void*)( fifo->data + fifo->readIdx * fifo->entrySize );
276 }
277
278 /* Return direct pointer to data instead of copying to user buffer.
279 This function is not thread-safe. */
280 void fc_fifo_read_single_done(FC_FIFO buffer, unsigned int pid)
281 {
282 volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
283
284 // operation to numData must be atomic since it
285 // is incremented and decremented by at least 2 separate process
286 // (fcmanager and process using libfc.so) even in single mode.
287 //fifo->numData--;
288 __sync_fetch_and_sub(&fifo->numData, 1);
289
290 if ( fifo->readIdx >= (fifo->numEntry-1) )
291 {
292 fifo->readIdx = 0;
293 }
294 else
295 {
296 fifo->readIdx++;
297 }
298
299 RELEASE_LOCK();
300 }
301
302 /* write 'size' bytes to 'fifo', from 'buffer', for the process 'ID' */
303 void* fc_fifo_write_single(FC_FIFO buffer, unsigned int size, unsigned int pid)
304 {
305 volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
306
307 /* check buffer size */
308 if (size > fifo->entrySize)
309 {
310 fc_message("write %d bytes to buffer is greater than FIFO element size (%d bytes).\n", size, fifo->entrySize);
311 return (0);
312 }
313
314 for(;;)
315 {
316 ACQUIRE_LOCK();
317
318 /* check if data is available for reading */
319 if ( fifo->numData == fifo->numEntry )
320 {
321 /* alone already */
322 if (fifo->refCount <= 1)
323 {
324 RELEASE_LOCK();
325 return 0;
326 }
327
328 RELEASE_LOCK();
329
330 SLEEP();
331 }
332 else
333 {
334 break;
335 }
336 }
337
338 return (void*)( fifo->data + fifo->writeIdx * fifo->entrySize );
339 }
340
341 void fc_fifo_write_single_done(FC_FIFO buffer, unsigned int pid)
342 {
343 volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
344
345 // operation to numData must be atomic since it
346 // is incremented and decremented by at least 2 separate process
347 // (fcmanager and process using libfc.so) even in single mode.
348 //fifo->numData++;
349 __sync_fetch_and_add(&fifo->numData, 1);
350
351 if ( fifo->writeIdx >= (fifo->numEntry-1) )
352 {
353 fifo->writeIdx = 0;
354 }
355 else
356 {
357 fifo->writeIdx++;
358 }
359
360 RELEASE_LOCK();
361 }
362
363 int fc_fifo_read_init(FC_FIFO buffer, void* init, unsigned int size, unsigned int pid)
364 {
365 volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
366
367 if (size != sizeof(FC_INIT))
368 {
369 fc_message("invalid read FC_INIT structure size\n");
370 return 0;
371 }
372
373 ACQUIRE_LOCK();
374
375 memcpy(init, (void*)&(fifo->init), sizeof(fifo->init));
376
377 RELEASE_LOCK();
378
379 return 1;
380 }
381
382 int fc_fifo_write_init(FC_FIFO buffer, void* init, unsigned int size, unsigned int pid)
383 {
384 volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
385
386 if (size != sizeof(FC_INIT))
387 {
388 fc_message("invalid write FC_INIT structure size\n");
389 return 0;
390 }
391
392 ACQUIRE_LOCK();
393
394 memcpy((void*)&(fifo->init), init, sizeof(fifo->init));
395
396 RELEASE_LOCK();
397
398 return 1;
399 }
400
401 int fc_fifo_read_ldyn(FC_FIFO buffer, void* ldyn, unsigned int size, unsigned int pid)
402 {
403 volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
404
405 if (size != sizeof(FC_LDYN))
406 {
407 fc_message("invalid FC_LDYN structure size\n");
408 return 0;
409 }
410
411 ACQUIRE_LOCK();
412
413 if ( fifo->lastLdynPtr == 0 )
414 {
415 fifo->lastLdynPtr = (FC_LDYN*)&(fifo->ldyn);
416 }
417
418 if ( fifo->lastLdynPtr == &(fifo->lastLdynPtr[MAX_LDYN-1]) )
419 {
420 fc_message("all FC_LDYN structures are read already.\n");
421 }
422
423 if ( (*(fifo->lastLdynPtr)).addr == 0 &&
424 (*(fifo->lastLdynPtr)).name[0] == '\0' )
425 {
426 memset(ldyn, 0, sizeof(FC_LDYN));
427 }
428 else
429 {
430 memcpy(ldyn, fifo->lastLdynPtr, sizeof(FC_LDYN));
431 fifo->lastLdynPtr++;
432 }
433
434 RELEASE_LOCK();
435
436 return 1;
437 }
438
439 int fc_fifo_write_ldyn(FC_FIFO buffer, void* ldyn, unsigned int size, unsigned int pid)
440 {
441 volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
442
443 int ctr;
444
445 if (size != sizeof(FC_LDYN))
446 {
447 fc_message("invalid FC_LDYN structure size\n");
448 return 0;
449 }
450
451 ACQUIRE_LOCK();
452
453 /* find available empty slot */
454 for (ctr = 0; ctr < (MAX_LDYN-1); ctr++)
455 {
456 if ( fifo->ldyn[ctr].addr == 0 &&
457 fifo->ldyn[ctr].name[0] == '\0' )
458 {
459 memcpy((void*)&(fifo->ldyn[ctr]), ldyn, sizeof(fifo->ldyn[0]));
460 break;
461 }
462 }
463
464 if (ctr == (MAX_LDYN-1))
465 {
466 fc_message("maximum FC_LDYN structures (%d) reached!\n", MAX_LDYN-1);
467 }
468
469 RELEASE_LOCK();
470
471 return 1;
472 }
473