1 : /*
2 : * This file is part of MIN Test Framework. Copyright © 2008 Nokia Corporation
3 : * and/or its subsidiary(-ies).
4 : * Contact: Konrad Marek Zapalowicz
5 : * Contact e-mail: DG.MIN-Support@nokia.com
6 : *
7 : * This program is free software: you can redistribute it and/or modify it
8 : * under the terms of the GNU General Public License as published by the Free
9 : * Software Foundation, version 2 of the License.
10 : *
11 : * This program is distributed in the hope that it will be useful, but WITHOUT
12 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 : * more details. You should have received a copy of the GNU General Public
15 : * License along with this program. If not, see
16 : * <http://www.gnu.org/licenses/>.
17 : */
18 :
19 :
20 : /**
21 : * @file min_ipc_mechanism.c
22 : * @version 0.1
23 : * @brief This file contains implementation of the IPC Mechanism of MIN
24 : */
25 :
26 : /* ------------------------------------------------------------------------- */
27 : /* INCLUDE FILES */
28 : #include "min_ipc_mechanism.h"
29 :
30 : /* ------------------------------------------------------------------------- */
31 : /* EXTERNAL DATA STRUCTURES */
32 : /* None */
33 :
34 : /* ------------------------------------------------------------------------- */
35 : /* EXTERNAL GLOBAL VARIABLES */
36 : /* None */
37 :
38 : /* ------------------------------------------------------------------------- */
39 : /* EXTERNAL FUNCTION PROTOTYPES */
40 : /* None */
41 :
42 : /* ------------------------------------------------------------------------- */
43 : /* GLOBAL VARIABLES */
44 : LOCAL int __shm_handler__ = -1;
45 :
46 : LOCAL DLList *__shm_handlers__ = INITPTR;
47 : /* ------------------------------------------------------------------------- */
48 : /* CONSTANTS */
49 : /* None */
50 :
51 : /* ------------------------------------------------------------------------- */
52 : /* MACROS */
53 :
54 : /* ------------------------------------------------------------------------- */
55 : /* LOCAL GLOBAL VARIABLES */
56 : /* ------------------------------------------------------------------------- */
57 : /** Buffer for messages that are waiting to be send */
58 : LOCAL DLList *msg_buffer = INITPTR;
59 : /* ------------------------------------------------------------------------- */
60 : /** PID of process that has called mq_open_queue.
61 : * We need to keep a track of process we are in because fork will copy
62 : * msg_buffer so it will be redundand. Solution is to flush the buffer when
63 : * pid will change = situation where there is one buffer per process
64 : */
65 : LOCAL pid_t lastpid = 0;
66 : /* ------------------------------------------------------------------------- */
67 : /* LOCAL CONSTANTS AND MACROS */
68 : /* None */
69 :
70 : /* ------------------------------------------------------------------------- */
71 : /* MODULE DATA STRUCTURES */
72 : /* None */
73 :
74 : /* ------------------------------------------------------------------------- */
75 : /* LOCAL FUNCTION PROTOTYPES */
76 : /* None */
77 : /* ------------------------------------------------------------------------- */
78 : /** Wrapps around system call msgsnd, it also has error handling included */
79 : LOCAL int mq_wrapper_around_msgsnd (int msqid, MsgBuffer * buf);
80 : /* ------------------------------------------------------------------------- */
81 : /** Translates MsgBuffer to _MIBuff */
82 : LOCAL void mq_msgbuf_to_internal (struct _MIBuff *ibuf,
83 : const MsgBuffer * buf);
84 : /* ------------------------------------------------------------------------- */
85 : /** Translates _MIBuff to MsgBuffer */
86 : LOCAL void mq_internal_to_msgbuf (MsgBuffer * buf,
87 : const struct _MIBuff *ibuf);
88 : /* ------------------------------------------------------------------------- */
89 : /** Gives the size of internal buffer in bytes */
90 : LOCAL unsigned int mq_internal_length (const struct _MIBuff *ibuf);
91 : /* ------------------------------------------------------------------------- */
92 : LOCAL int _findShmKey(const void *a, const void *b);
93 : /* ------------------------------------------------------------------------- */
94 : LOCAL int _findShmShmid(const void *a, const void *b);
95 : /* ------------------------------------------------------------------------- */
96 : /* FORWARD DECLARATIONS */
97 : /* None */
98 :
99 : /* ------------------------------------------------------------------------- */
100 : /* ==================== LOCAL FUNCTIONS ==================================== */
101 : /* ------------------------------------------------------------------------- */
102 : LOCAL int mq_wrapper_around_msgsnd (int msqid, MsgBuffer * buf)
103 5859 : {
104 5859 : int retval = ENOERR;
105 5859 : int result = ENOERR;
106 5859 : unsigned int length = sizeof (struct _MIBuff) - sizeof (long);
107 : struct _MIBuff ibuf;
108 5859 : struct _MIBuff *ptr2ibf = INITPTR;
109 5859 : DLListIterator it = DLListNULLIterator;
110 :
111 5859 : if (buf == INITPTR) {
112 0 : retval = -1;
113 0 : goto EXIT;
114 : }
115 :
116 : /* lets try to send some buffered first, buffer has to be FIFO */
117 5859 : result = 0;
118 5859 : it = dl_list_head (msg_buffer);
119 11718 : while ((result != -1) && (it != DLListNULLIterator)) {
120 :
121 : /* try to send message from the buffer */
122 0 : ptr2ibf = (struct _MIBuff *)dl_list_data (it);
123 0 : length = mq_internal_length (ptr2ibf);
124 0 : result = msgsnd (msqid, ptr2ibf, length, IPC_NOWAIT);
125 :
126 : /* if successfull then remove it from the buffer */
127 0 : if (result != -1) {
128 0 : free (dl_list_data (it));
129 0 : dl_list_remove_it (it);
130 0 : it = dl_list_head (msg_buffer);
131 : }
132 : }
133 :
134 : /* now lets try to send orginal message */
135 5859 : mq_msgbuf_to_internal (&ibuf, buf);
136 5859 : length = mq_internal_length (&ibuf);
137 5859 : result = msgsnd (msqid, &ibuf, length, IPC_NOWAIT);
138 :
139 : /* Sending has failed, now we have to examine errno */
140 5859 : if (result == -1) {
141 0 : switch (errno) {
142 : case EAGAIN:
143 0 : MIN_NOTICE ("MQ is full - message will be buffered");
144 : /* Queue is full, we need to buffer the msg */
145 : /* If buffer is not created then allocate it */
146 0 : if (msg_buffer == INITPTR) {
147 0 : msg_buffer = dl_list_create ();
148 : }
149 :
150 : /* Create new message buffer and copy message */
151 0 : ptr2ibf = NEW (struct _MIBuff);
152 0 : memcpy (ptr2ibf, &ibuf, sizeof (struct _MIBuff));
153 :
154 : /* Put message into the buffer */
155 0 : dl_list_add (msg_buffer, (void *)ptr2ibf);
156 :
157 0 : break;
158 : default:
159 : /* EINVAL, EACCES, EFAULT, EINTR */
160 0 : MIN_ERROR ("MQ Error: %s",strerror (errno));
161 0 : retval = -1;
162 : }
163 : }
164 5859 : EXIT:
165 5859 : return retval;
166 : }
167 :
168 : /* ------------------------------------------------------------------------- */
169 : LOCAL void mq_msgbuf_to_internal (struct _MIBuff *ibuf, const MsgBuffer * buf)
170 5864 : {
171 5864 : if (ibuf == INITPTR) {
172 0 : return;
173 : }
174 5864 : if (buf == INITPTR) {
175 0 : return;
176 : }
177 :
178 5864 : ibuf->receiver_ = buf->receiver_;
179 5864 : ibuf->sender_ = buf->sender_;
180 5864 : ibuf->type_ = buf->type_;
181 5864 : ibuf->param_ = buf->param_;
182 5864 : ibuf->special_ = buf->special_;
183 5864 : ibuf->extif_msg_type_ = buf->extif_msg_type_;
184 :
185 5864 : ibuf->msgbeg_ = strlen (buf->desc_) + 1;
186 5864 : STRCPY (ibuf->desc_, buf->desc_, ibuf->msgbeg_);
187 5864 : STRCPY (&ibuf->desc_[ibuf->msgbeg_], buf->message_,
188 : strlen (buf->message_) + 1);
189 : }
190 :
191 : /* ------------------------------------------------------------------------- */
192 : LOCAL void mq_internal_to_msgbuf (MsgBuffer * buf, const struct _MIBuff *ibuf)
193 4324 : {
194 4324 : if (buf == INITPTR) {
195 0 : return;
196 : }
197 4324 : if (ibuf == INITPTR) {
198 0 : return;
199 : }
200 :
201 4324 : memset (buf, 0x0, sizeof (MsgBuffer));
202 :
203 4324 : buf->receiver_ = ibuf->receiver_;
204 4324 : buf->sender_ = ibuf->sender_;
205 4324 : buf->type_ = ibuf->type_;
206 4324 : buf->param_ = ibuf->param_;
207 4324 : buf->special_ = ibuf->special_;
208 4324 : buf->extif_msg_type_ = ibuf->extif_msg_type_;
209 :
210 4324 : STRCPY (buf->desc_, ibuf->desc_, ibuf->msgbeg_);
211 4324 : STRCPY (buf->message_, &ibuf->desc_[ibuf->msgbeg_], MaxMsgSize);
212 : }
213 :
214 : /* ------------------------------------------------------------------------- */
215 : LOCAL unsigned int mq_internal_length (const struct _MIBuff *ibuf)
216 5864 : {
217 : unsigned int base_length = sizeof (long) * 2 + sizeof (char)
218 : + sizeof (int) * 2 + sizeof (unsigned short)
219 : + sizeof (MINMsgType)
220 5864 : + sizeof (TMSCommand);
221 5864 : unsigned int length = 0;
222 :
223 5864 : if (ibuf == INITPTR) {
224 0 : goto EXIT;
225 : }
226 5864 : length = base_length
227 : + strlen (ibuf->desc_) + 1
228 : + strlen (&ibuf->desc_[ibuf->msgbeg_]) + 1;
229 5864 : EXIT:
230 5864 : return length;
231 : }
232 :
233 : /* ------------------------------------------------------------------------- */
234 : LOCAL int _findShmKey(const void *a, const void *b)
235 730 : {
236 730 : const key_t *p1 = (const key_t*)b;
237 730 : const struct ShmItem *p2 = (const struct ShmItem*)a;
238 :
239 730 : if ((*p1)==p2->key_) return 0;
240 0 : else return -1;
241 : }
242 : /* ------------------------------------------------------------------------- */
243 : LOCAL int _findShmShmid(const void *a, const void *b)
244 42 : {
245 42 : const int *p1 = (const int*)b;
246 42 : const struct ShmItem *p2 = (const struct ShmItem*)a;
247 :
248 42 : if ((*p1)==p2->shmid_) return 0;
249 24 : else return -1;
250 : }
251 : /* ------------------------------------------------------------------------- */
252 : /* ======================== FUNCTIONS ====================================== */
253 : /* ------------------------------------------------------------------------- */
254 : /** Checks if queue of a given id already exists.
255 : * @param queueid queue id, which is 8bit number. Char can be used instead.
256 : * @return 0 when queue exists, 1 when queue does not exists, -1 in case of
257 : * failure.
258 : */
259 : int mq_queue_exists (int queueid)
260 0 : {
261 0 : int retval = -1;
262 0 : char *path = "/tmp";
263 0 : key_t key = ftok (path, queueid);
264 0 : int msqid = -1;
265 0 : if (key == -1) {
266 0 : MIN_FATAL ("Key for queue not created");
267 0 : errno = EFAULT;
268 : }
269 : else {
270 0 : msqid = msgget (key, IPC_CREAT | IPC_EXCL | 0660);
271 : }
272 0 : if (msqid == -1) {
273 0 : if (errno == EEXIST)
274 0 : retval = 1;
275 : else
276 0 : retval = -1;
277 : } else
278 0 : retval = 0;
279 0 : return retval;
280 : }
281 :
282 : /* ------------------------------------------------------------------------- */
283 : void mq_init_buffer ()
284 737 : {
285 737 : DLListIterator it = DLListNULLIterator;
286 :
287 : /* Prepare the buffer */
288 737 : if (msg_buffer == INITPTR) {
289 : /* If buffer is not created then allocate it */
290 252 : msg_buffer = dl_list_create ();
291 252 : lastpid = getpid ();
292 : } else {
293 : /* Buffer exists, need to check PID. if PID differs
294 : * from lastpid then we are a new process and flushing of
295 : * buffer is needed. Otherwise it is ok.
296 : */
297 485 : if (lastpid != getpid ()) {
298 : /* correct the lastpid value */
299 106 : lastpid = getpid ();
300 :
301 : /* we are a new process, flush the buffer */
302 : /* but not destroy the buffer */
303 106 : it = dl_list_head (msg_buffer);
304 212 : while (it != DLListNULLIterator) {
305 0 : free (dl_list_data (it));
306 0 : dl_list_remove_it (it);
307 0 : it = dl_list_head (msg_buffer);
308 : }
309 : }
310 : }
311 737 : }
312 :
313 : /* ------------------------------------------------------------------------- */
314 : /** Creates a new message queue, if queue identified by given key already
315 : * exists its id is returned.
316 : * @param queueid queue id, which is 8bit number. Char can be used instead
317 : * @return queue id number, or -1 in case of failure
318 : *
319 : * Possible Errors:
320 : * - ENOSPC Maximum number of allowed message queue has been reached.
321 : * - EFAULT Error in opening.
322 : */
323 : int mq_open_queue (int queueid)
324 725 : {
325 725 : char *path = "/tmp";
326 725 : key_t key = ftok (path, queueid);
327 725 : int msqid = -1;
328 :
329 : /* create queue */
330 725 : if (key == -1) {
331 0 : MIN_FATAL ("Key for queue not created");
332 0 : errno = EFAULT;
333 0 : goto EXIT;
334 : } else {
335 725 : msqid = msgget (key, IPC_CREAT | 0660);
336 725 : if (msqid == -1) {
337 0 : MIN_FATAL ("MQ not created: %s",strerror (errno));
338 : }
339 : }
340 :
341 725 : mq_init_buffer ();
342 725 : EXIT:
343 725 : return msqid;
344 : }
345 :
346 : /* ------------------------------------------------------------------------- */
347 : /** Closes message queue. The queue is removed from the system.
348 : * @param msqid message queue identifier.
349 : * @return 0 on success, -1 on failure
350 : */
351 : int mq_close_queue (int msqid)
352 39 : {
353 : /* flush the buffer */
354 39 : mq_flush_msg_buffer ();
355 :
356 : /* close queue */
357 39 : if (msgctl (msqid, IPC_RMID, 0) == -1) {
358 0 : MIN_ERROR ("Error when closing MQ");
359 0 : return -1;
360 : }
361 : else
362 39 : return 0;
363 : }
364 :
365 : /* ------------------------------------------------------------------------- */
366 : /** Sends message to the queue.
367 : * @param msqid message queue identifier
368 : * @param buf pointer to buffer with data to send
369 : * @return 0 when succeded, or -1 in case of failure
370 : */
371 : int mq_send_message (int msqid, MsgBuffer * buf)
372 4520 : {
373 4520 : return mq_wrapper_around_msgsnd (msqid, buf);
374 : }
375 :
376 : /* ------------------------------------------------------------------------- */
377 : /** Sends message to the queue in a blocking way.
378 : * @param msqid message queue identifier
379 : * @param buf pointer to buffer with data to send
380 : * @return 0 when succeded, or -1 in case of failure
381 : */
382 : int mq_send_message_block (int msqid, MsgBuffer * buf)
383 5 : {
384 5 : unsigned int length = sizeof (struct _MIBuff) - sizeof (long);
385 : struct _MIBuff ibuf;
386 :
387 5 : mq_msgbuf_to_internal (&ibuf, buf);
388 :
389 5 : MIN_DEBUG ("%d -> %d [%d]\n", ibuf.sender_, ibuf.receiver_,
390 : ibuf.type_);
391 5 : length = mq_internal_length (&ibuf);
392 5 : return msgsnd (msqid, &ibuf, length, 0);
393 : }
394 :
395 : /* ------------------------------------------------------------------------- */
396 : /** Sends message to the queue.
397 : * @param msqid message queue identifier
398 : * @param adress pid of the recieving process
399 : * @param type message type, @see MINMsgType
400 : * @param param message parameter, its value depends on message type
401 : * @param msg custom parameter, description of the message, depends on type
402 : * of the message.
403 : * @return 0 when succeded, or -1 in case of failure
404 : */
405 : int mq_send_message2 (int msqid, long adress, MINMsgType type, int param,
406 : const char *msg)
407 1339 : {
408 : MsgBuffer buf;
409 :
410 : /* construct the message */
411 1339 : buf.receiver_ = adress;
412 1339 : buf.sender_ = getpid ();
413 1339 : buf.type_ = type;
414 1339 : buf.param_ = param;
415 1339 : STRCPY (buf.desc_, "\0", MaxDescSize);
416 1339 : STRCPY (buf.message_, msg, MaxMsgSize);
417 :
418 1339 : MIN_DEBUG ("%d -> %d [%d]\n", buf.sender_, buf.receiver_, type);
419 :
420 1339 : return mq_wrapper_around_msgsnd (msqid, &buf);
421 : }
422 :
423 : /* ------------------------------------------------------------------------- */
424 : /** Sends message to the queue in a blocking way.
425 : * @param msqid message queue identifier
426 : * @param adress pid of the recieving process
427 : * @param type message type, @see MINMsgType
428 : * @param param message parameter, its value depends on message type
429 : * @param msg custom parameter, description of the message, depends on type
430 : * of the message.
431 : * @return 0 when succeded, or -1 in case of failure
432 : */
433 : int mq_send_message2_block (int msqid, long adress, MINMsgType type,
434 : int param, const char *msg)
435 0 : {
436 : struct _MIBuff ibuf;
437 0 : unsigned int length = sizeof (struct _MIBuff) - sizeof (long);
438 :
439 : /* construct the message */
440 0 : ibuf.receiver_ = adress;
441 0 : ibuf.sender_ = getpid ();
442 0 : ibuf.type_ = type;
443 0 : ibuf.param_ = param;
444 0 : STRCPY (ibuf.desc_, "\0", MaxDescSize);
445 0 : STRCPY (ibuf.desc_, msg, MaxMsgSize);
446 :
447 0 : MIN_DEBUG ("%d -> %d [%d]\n", ibuf.sender_, ibuf.receiver_, type);
448 :
449 0 : return msgsnd (msqid, &ibuf, length, 0);
450 : }
451 :
452 : /* ------------------------------------------------------------------------- */
453 : /** Reads message from queue.
454 : * @param msqid message queue identifier
455 : * @param msg_type the type of message we are going to read
456 : * @param buf pointer to the buffer for incomming message
457 : * @return number of bytes recieved, or -1 in case of error
458 : *
459 : * Possible Errors:
460 : * - EINVAL invalid value is passed to the function
461 : * - EINTR function interrupted by the signal
462 : * - EIDRM queue identifier removed from the system
463 : * - E2BIG message to big to be recieved
464 : */
465 : int mq_read_message (int msqid, long msg_type, MsgBuffer * buf)
466 4324 : {
467 4324 : unsigned int length = sizeof (struct _MIBuff) - sizeof (long);
468 4324 : int retval = ENOERR;
469 4324 : int result = 0;
470 4324 : TSBool msgread = ESFalse;
471 4324 : DLListIterator it = DLListNULLIterator;
472 4324 : struct _MIBuff *ipom = INITPTR;
473 : struct _MIBuff ibuf;
474 :
475 4324 : memset (&ibuf, 0x0, sizeof (struct _MIBuff));
476 :
477 : while (1) {
478 :
479 : /* peek for message in MQ */
480 5887 : if (mq_peek_message (msqid, msg_type) == 1) {
481 4324 : length = sizeof (struct _MIBuff) - sizeof (long);
482 4324 : retval = msgrcv (msqid, &ibuf, length, msg_type, 0);
483 4324 : if (retval==(ssize_t)-1) {
484 0 : MIN_FATAL("Message in queue way too big to be recieved, error: %d",errno);
485 : } else {
486 4324 : MIN_DEBUG("Read message of size: %d",retval);
487 : }
488 4324 : mq_internal_to_msgbuf (buf, &ibuf);
489 4324 : msgread = ESTrue;
490 : }
491 :
492 : /* try to send buffered */
493 5887 : result = 0;
494 5887 : it = dl_list_head (msg_buffer);
495 11774 : while ((it != DLListNULLIterator) && (result != -1)) {
496 :
497 : /* try to send message from the buffer */
498 0 : ipom = (struct _MIBuff *)dl_list_data (it);
499 0 : length = mq_internal_length (ipom);
500 0 : result = msgsnd (msqid, ipom, length, IPC_NOWAIT);
501 :
502 : /* if successfull then remove it from the buffer */
503 0 : if (result != -1) {
504 0 : free (dl_list_data (it));
505 0 : dl_list_remove_it (it);
506 0 : it = dl_list_head (msg_buffer);
507 : }
508 : }
509 :
510 : /* break the loop if msg was read from the queue */
511 5887 : if (msgread == ESTrue) {
512 4324 : break;
513 : }
514 :
515 : /* slow down a little bit this fast loop */
516 1563 : usleep (10000);
517 1563 : }
518 :
519 4324 : return retval;
520 : }
521 :
522 : /* ------------------------------------------------------------------------- */
523 : /** Peeks message queue to see if mesage of given type has arrived. This
524 : * function is no blocking.
525 : * @param msqid message queue identifier
526 : * @param msg_type the type of message we are waiting for. If == 0 then
527 : * messages of all types will be metched.
528 : * @return 1 when message arrives, 0 when there is no message.
529 : */
530 : int mq_peek_message (int msqid, long msg_type)
531 26838 : {
532 : int result =
533 26838 : msgrcv (msqid, NULL, 0, msg_type, IPC_NOWAIT);
534 26838 : if (result == -1 && errno == E2BIG)
535 8649 : return 1;
536 : else
537 18189 : return 0;
538 : }
539 :
540 : /* ------------------------------------------------------------------------- */
541 : /** Flushes msg_buffer */
542 : void mq_flush_msg_buffer ()
543 220 : {
544 220 : DLListIterator it = DLListNULLIterator;
545 :
546 : /* check size of the buffer */
547 220 : MIN_DEBUG ("There are %d messages buffered."
548 : " Buffer will be flushed", dl_list_size (msg_buffer));
549 :
550 : /* flush the buffer and destroy it */
551 220 : it = dl_list_head (msg_buffer);
552 440 : while (it != DLListNULLIterator) {
553 0 : free (dl_list_data (it));
554 0 : dl_list_remove_it (it);
555 0 : it = dl_list_head (msg_buffer);
556 : }
557 220 : dl_list_free (&msg_buffer);
558 :
559 : /* set lastpid */
560 220 : lastpid = 0;
561 220 : }
562 :
563 : /* ------------------------------------------------------------------------- */
564 : /** Resends messages from the buffer. */
565 : void mq_resend_buffered ()
566 91 : {
567 : /* obtain id of a queue. It is kind of a hack, queue id should come
568 : * as a parameter, but to avoid extern we are doing it this way. */
569 91 : int msqid = mq_open_queue ('a');
570 91 : int result = 0;
571 91 : unsigned int length = sizeof (struct _MIBuff) - sizeof (long);
572 91 : DLListIterator it = dl_list_head (msg_buffer);
573 91 : struct _MIBuff *ptr2ibf = INITPTR;
574 :
575 : /* sending was successfull, lets try to send some buffered */
576 182 : while ((it != DLListNULLIterator)) {
577 :
578 : /* try to send message from the buffer */
579 0 : ptr2ibf = (struct _MIBuff *)dl_list_data (it);
580 0 : length = mq_internal_length (ptr2ibf);
581 0 : result = msgsnd (msqid, ptr2ibf, length, IPC_NOWAIT);
582 :
583 : /* if successfull then remove it from the buffer */
584 0 : if (result != -1) {
585 0 : free (dl_list_data (it));
586 0 : dl_list_remove_it (it);
587 0 : it = dl_list_head (msg_buffer);
588 : }
589 :
590 0 : usleep (10000);
591 : }
592 91 : }
593 :
594 : /* ------------------------------------------------------------------------- */
595 : int mq_buffer_size ()
596 0 : {
597 0 : return dl_list_size (msg_buffer);
598 : }
599 :
600 : /* ------------------------------------------------------------------------- */
601 : /** Pauses process.
602 : * @param pid the id of a process to be paused (>0)
603 : * @return 0 on success and -1 on failure
604 : *
605 : * Possible Errors:
606 : * - EINVAL invalid value was passed to the funcion
607 : * - ESRCH there is no process of a given pid
608 : * - EPERM calling process has no permission to send a signal
609 : */
610 : int sl_pause_process (long pid)
611 0 : {
612 0 : int retval = -1;
613 0 : if (pid != 0)
614 0 : retval = kill (pid, SIGSTOP);
615 : else {
616 0 : MIN_WARN ("Given pid is invalid");
617 0 : errno = EINVAL;
618 : }
619 0 : return retval;
620 : }
621 :
622 : /* ------------------------------------------------------------------------- */
623 : /** Pauses process.
624 : * @param pid the id of a process to be resumed (>0)
625 : * @return 0 on success and -1 on failure
626 : *
627 : * Possible Errors:
628 : * - EINVAL invalid value was passed to the funcion
629 : * - ESRCH there is no process of a given pid
630 : * - EPERM calling process has no permission to send a signal
631 : */
632 : int sl_resume_process (long pid)
633 0 : {
634 0 : int retval = -1;
635 0 : retval = kill (pid, SIGCONT);
636 0 : return retval;
637 : }
638 :
639 : /* ------------------------------------------------------------------------- */
640 : /** Pauses process.
641 : * @param pid the id of a process to be killed (>0)
642 : * @return 0 on success and -1 on failure
643 : *
644 : * Possible Errors:
645 : * - EINVAL invalid value was passed to the funcion
646 : * - ESRCH there is no process of a given pid
647 : * - EPERM calling process has no permission to send a signal
648 : */
649 : int sl_kill_process (long pid)
650 0 : {
651 0 : int retval = -1;
652 0 : retval = kill (pid, SIGKILL);
653 0 : return retval;
654 : }
655 :
656 : /* ------------------------------------------------------------------------- */
657 : /** Sets signal handler for the given signal.
658 : * @param signum is the signal id
659 : * @param sighal pointer to the signal handler function.
660 : * @return -1 on failure, 0 on success.
661 : */
662 : int sl_set_sighandler (int signum, sighandler_t sighal)
663 1649 : {
664 1649 : int retval = -1;
665 : struct sigaction new_action;
666 1649 : new_action.sa_handler = sighal;
667 1649 : sigfillset (&new_action.sa_mask);
668 1649 : new_action.sa_flags = SA_NOCLDSTOP;
669 1649 : retval = sigaction (signum, &new_action, NULL);
670 1649 : return retval;
671 : }
672 :
673 : /* ------------------------------------------------------------------------- */
674 : /** Gets shared memory segment
675 : * @param shmgetid [in] key used when requesting shared memmory segment. 8bit
676 : * @param size [in] the size of shared memory segment.
677 : * @return shared memory id or -1 in case of failure.
678 : *
679 : * Possible Errors:
680 : * - EFAULT: error in function
681 : */
682 : int sm_create (int shmgetid, unsigned int size)
683 959 : {
684 959 : char *path = "/tmp";
685 : key_t key;
686 959 : struct ShmItem *tmp = INITPTR;
687 959 : DLListIterator it = DLListNULLIterator;
688 :
689 959 : key = ftok (path, shmgetid);
690 959 : if (key == -1) {
691 0 : MIN_FATAL ("Key for SM not created");
692 0 : errno = EFAULT;
693 0 : return -1;
694 : }
695 :
696 959 : if (__shm_handlers__==INITPTR) { __shm_handlers__ = dl_list_create(); }
697 : else {
698 730 : it = dl_list_find(dl_list_head(__shm_handlers__),
699 : dl_list_tail(__shm_handlers__),
700 : _findShmKey, &key);
701 : }
702 :
703 959 : if (it==DLListNULLIterator) {
704 229 : tmp = NEW(struct ShmItem);
705 229 : tmp->key_ = key;
706 229 : tmp->shmid_ = shmget (key, size, IPC_CREAT | 0660);
707 229 : dl_list_add(__shm_handlers__,tmp);
708 229 : return tmp->shmid_;
709 : } else {
710 730 : return ((struct ShmItem*)dl_list_data(it))->shmid_;
711 : }
712 : }
713 :
714 : /* ------------------------------------------------------------------------- */
715 : /** Marks shared memory segment to be destroyed.
716 : * @param shmid [in] the id of the shared memory segment to be destroyed.
717 : * @return 0 in case of success, -1 otherwise.
718 : */
719 : int sm_destroy (int shmid)
720 43 : {
721 43 : DLListIterator it = DLListNULLIterator;
722 43 : it = dl_list_find(dl_list_head(__shm_handlers__),
723 : dl_list_tail(__shm_handlers__),
724 : _findShmShmid, &shmid);
725 :
726 43 : if (it==DLListNULLIterator) {
727 25 : MIN_ERROR("Requested to remove not existing SHM %d",
728 : shmid);
729 25 : return -1;
730 : } else {
731 18 : if (shmctl (shmid, IPC_RMID, 0) == -1)
732 0 : return -1;
733 : else {
734 18 : free(dl_list_data(it));
735 18 : dl_list_remove_it(it);
736 18 : if (dl_list_size(__shm_handlers__)==0) {
737 18 : dl_list_free(&__shm_handlers__);
738 : }
739 18 : return 0;
740 : }
741 : }
742 : }
743 :
744 : /* ------------------------------------------------------------------------- */
745 : /** Returns pointer to the allocated shared memory segment.
746 : * @param shmid [in] id of the shared memory segment we want to be attached to
747 : * @return pointer to the SH segment, or INITPTR in case of failure.
748 : */
749 : void *sm_attach (int shmid)
750 1015 : {
751 1015 : int *retval = (int *)shmat (shmid, (void *)NULL, 0);
752 1015 : if (*retval == -1) {
753 0 : MIN_WARN ("Could not find allocated memory segment");
754 0 : return INITPTR;
755 : }
756 : else
757 1015 : return (void *)retval;
758 : }
759 :
760 : /* ------------------------------------------------------------------------- */
761 : inline void sm_detach (void *shmaddr)
762 1015 : {
763 1015 : if (shmaddr != INITPTR)
764 1015 : shmdt (shmaddr);
765 1015 : }
766 :
767 : /* ------------------------------------------------------------------------- */
768 : int sm_read (const void *shmaddr, void *data, unsigned int size)
769 965 : {
770 965 : int retval = ENOERR;
771 965 : if (shmaddr == INITPTR) {
772 0 : errno = EINVAL;
773 0 : retval = -1;
774 0 : goto EXIT;
775 : }
776 965 : if (data == INITPTR) {
777 0 : errno = EINVAL;
778 0 : retval = -1;
779 0 : goto EXIT;
780 : }
781 :
782 965 : memcpy (data, shmaddr, size);
783 965 : EXIT:
784 965 : return retval;
785 : }
786 :
787 : /* ------------------------------------------------------------------------- */
788 : int sm_write (void *shmaddr, const void *data, unsigned int size)
789 208 : {
790 208 : int retval = ENOERR;
791 208 : if (shmaddr == INITPTR) {
792 0 : errno = EINVAL;
793 0 : retval = -1;
794 0 : goto EXIT;
795 : }
796 208 : if (data == INITPTR) {
797 0 : errno = EINVAL;
798 0 : retval = -1;
799 0 : goto EXIT;
800 : }
801 :
802 208 : memcpy (shmaddr, data, size);
803 208 : EXIT:
804 208 : return retval;
805 : }
806 :
807 : /* ------------------------------------------------------------------------- */
808 : int sm_get_handler()
809 0 : {
810 0 : return __shm_handler__;
811 : }
812 : /* ------------------------------------------------------------------------- */
813 : /** Returns the size of SHM segment
814 : * @param shmid [in] id of the shared memory segment we want to be attached to
815 : * @return size of the segment or 0
816 : */
817 : size_t sm_get_segsz (int shmid)
818 54 : {
819 : struct shmid_ds shmid_ds;
820 :
821 54 : if (shmctl (shmid, IPC_STAT, &shmid_ds) == -1) {
822 0 : MIN_WARN ("shmget() failed: %s", strerror(errno));
823 0 : return 0;
824 : }
825 :
826 54 : return shmid_ds.shm_segsz;
827 : }
828 : /* ------------------------------------------------------------------------- */
829 :
830 : /* ================= OTHER EXPORTED FUNCTIONS ============================== */
831 : /* None */
832 :
833 : /* ------------------------------------------------------------------------- */
834 : /* ================= TESTS FOR LOCAL FUNCTIONS ============================= */
835 : #ifdef MIN_UNIT_TEST
836 : #include "min_ipc_mechanism.tests"
837 : #endif /* MIN_UNIT_TEST */
838 : /* ------------------------------------------------------------------------- */
839 : /* End of file */
|