OSDN Git Service

2003-05-28 Jeff Johnston <jjohnstn@redhat.com>
[pf3gnuchains/pf3gnuchains3x.git] / newlib / libc / sys / linux / linuxthreads / mq_notify.c
1 /* Copyright 2002, Red Hat Inc. */
2
3 #include <mqueue.h>
4 #include <unistd.h>
5 #include <errno.h>
6 #include <sys/ipc.h>
7 #include <sys/sem.h>
8 #include <string.h>
9
10 #include "internals.h"
11 #include <sys/lock.h>
12
13 #include "mqlocal.h"
14
15 static void *mq_notify_process (void *);
16
17 void
18 __cleanup_mq_notify (struct libc_mq *info)
19 {
20   struct sembuf sb4 = {4, 1, 0};
21   /* kill notification thread and allow other processes to set a notification */
22   pthread_cancel ((pthread_t)info->th);
23   semop (info->semid, &sb4, 1);
24 }
25   
26 static void *
27 mq_notify_process (void *arg)
28 {
29   struct libc_mq *info = (struct libc_mq *)arg;
30   struct sembuf sb3[2] = {{3, 0, 0}, {5, 0, 0}};
31   struct sembuf sb4 = {4, 1, 0};
32   int rc;
33
34   /* wait until queue is empty */
35   while (!(rc = semop (info->semid, sb3, 1)) && errno == EINTR)
36     /* empty */ ;
37
38   if (!rc)
39     {
40       /* now wait until there are 0 readers and the queue has something in it */
41       sb3[0].sem_op = -1;
42       while (!(rc = semop (info->semid, sb3, 2)) && errno == EINTR)
43         /* empty */ ;
44       /* restore value since we have not actually performed a read */
45       sb3[0].sem_op = 1;
46       semop (info->semid, sb3, 1);
47       /* perform desired notification - either run function in this thread or pass signal */
48       if (!rc)
49         {
50           if (info->sigevent->sigev_notify == SIGEV_SIGNAL)
51             raise (info->sigevent->sigev_signo);
52           else if (info->sigevent->sigev_notify == SIGEV_THREAD)
53             info->sigevent->sigev_notify_function (info->sigevent->sigev_value);
54           /* allow other processes to now mq_notify */
55           semop (info->semid, &sb4, 1);
56         }
57     }
58   pthread_exit (NULL);
59 }
60
61 int
62 mq_notify (mqd_t msgid, const struct sigevent *notification)
63 {
64   struct libc_mq *info;
65   struct sembuf sb4 = {4, -1, IPC_NOWAIT};
66   int rc;
67   pthread_attr_t *attr = NULL;
68
69   info = __find_mq (msgid);
70
71   if (info == NULL)
72     {
73       errno = EBADF;
74       return -1;
75     }
76
77   /* get notification lock */
78   rc = semop (info->semid, &sb4, 1);
79
80   if (rc == -1)
81     {
82       errno = EBUSY;
83       return -1;
84     }
85
86   /* to get the notification running we use a pthread - if the user has requested
87      an action in a pthread, we use the user's attributes when setting up the thread */
88   info->sigevent = (struct sigevent *)notification;
89   if (info->sigevent->sigev_notify == SIGEV_THREAD)
90     attr = (pthread_attr_t *)info->sigevent->sigev_notify_attributes;
91   rc = pthread_create ((pthread_t *)&info->th, attr, mq_notify_process, (void *)info);
92
93   if (rc != 0)
94     rc = -1;
95   else
96     info->cleanup_notify = &__cleanup_mq_notify;
97
98   return rc;
99 }
100
101       
102
103
104
105
106