OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [newlib-1.17.0/] [newlib/] [libc/] [sys/] [linux/] [mq_open.c] - Blame information for rev 438

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 148 jeremybenn
/* Copyright 2002, Red Hat Inc. */
2
 
3
#include <mqueue.h>
4
#include <fcntl.h>
5
#include <unistd.h>
6
#include <errno.h>
7
#include <sys/stat.h>
8
#include <sys/mman.h>
9
#include <sys/ipc.h>
10
#include <sys/sem.h>
11
#include <string.h>
12
#include <stdlib.h>
13
#include <time.h>
14
#include <stdarg.h>
15
#include <machine/weakalias.h>
16
#define _LIBC 1
17
#include <sys/lock.h>
18
#undef _LIBC
19
 
20
#include "mqlocal.h"
21
 
22
#define NHASH   32                /* Num of hash lists, must be a power of 2 */
23
#define LOCHASH(i)      ((i)&(NHASH-1))
24
 
25
static long     mq_index;       /* Index of next entry */
26
static struct   libc_mq *mq_hash[NHASH];   /* Hash list heads for mqopen_infos */
27
 
28
__LOCK_INIT(static, mq_hash_lock);
29
 
30
mqd_t
31
mq_open (const char *name, int oflag, ...)
32
{
33
  MSG *wrbuf = NULL;
34
  MSG *rdbuf = NULL;
35
  int msgqid = -1;
36
  int rc = -1;
37
  int fd = -1;
38
  int semid = -1;
39
  int created = 0;
40
  key_t key = (key_t)-1;
41
  struct mq_attr *attr = (struct mq_attr *)MAP_FAILED;
42
  struct sembuf sb = {0, 0, 0};
43
  mode_t mode = 0;
44
  int size;
45
  int i, index, saved_errno;
46
  char *real_name;
47
  char *ptr;
48
  struct mq_attr *user_attr = NULL;
49
  struct libc_mq *info;
50
  union semun arg;
51
 
52
  /* ignore opening slash if present */
53
  if (*name == '/')
54
    ++name;
55
  size = strlen(name);
56
 
57
  if ((real_name = (char *)malloc (size + sizeof(MSGQ_PREFIX))) == NULL ||
58
      (info = (struct libc_mq *)malloc (sizeof(struct libc_mq))) == NULL)
59
    {
60
      errno = ENOSPC;
61
      if (real_name)
62
        free (real_name);
63
      return (mqd_t)-1;
64
    }
65
 
66
  /* use given name to create shared memory file name - we convert any
67
     slashes to underscores so we don't have to create directories */
68
  memcpy (real_name, MSGQ_PREFIX, sizeof(MSGQ_PREFIX) - 1);
69
  memcpy (real_name + sizeof(MSGQ_PREFIX) - 1, name, size + 1);
70
  ptr = real_name + sizeof(MSGQ_PREFIX) - 1;
71
  for (i = 0; i < size; ++i)
72
    {
73
      if (*ptr == '/')
74
        *ptr = '_';
75
      ++ptr;
76
    }
77
 
78
  /* open shared memory file based on msg queue open flags and then use memory
79
     file to create a unique key to use for semaphores, etc.. */
80
  if (oflag & O_CREAT)
81
    {
82
      va_list list;
83
      va_start (list, oflag);
84
 
85
      saved_errno = errno;
86
      mode = (mode_t)va_arg (list, int);
87
      user_attr = va_arg(list,struct mq_attr *);
88
      va_end (list);
89
 
90
      /* attempt to open the shared memory file for exclusive create so we know
91
         whether we are the owners or not */
92
      fd = open (real_name, O_RDWR | O_CREAT | O_EXCL, mode);
93
      if (fd < 0 && (oflag & O_EXCL))
94
        {
95
          /* we failed and the user wanted exclusive create */
96
          free (real_name);
97
          free (info);
98
          return (mqd_t)-1;
99
        }
100
      errno = saved_errno;
101
      /* check if we created the file or not */
102
      if (fd >= 0)
103
        created = 1;
104
    }
105
 
106
  if (fd < 0)
107
    fd = open (real_name, O_RDWR, 0);
108
 
109
  if (fd >= 0)
110
    key = ftok(real_name, 255);
111
 
112
  if (key != (key_t)-1)
113
    /* memory map the shared memory file so we have a global shared data area to use */
114
    attr = (struct mq_attr *)mmap (0, sizeof(struct mq_attr), PROT_READ | PROT_WRITE,
115
                                   MAP_SHARED, fd, 0);
116
 
117
  if (attr != (struct mq_attr *)MAP_FAILED)
118
    {
119
      /* we need semaphores to prevent multi-process race conditions on the
120
         shared storage which contains a shared structure.  The following
121
         are the ones we need.
122
 
123
 
124
         1 = number of opens
125
         2 = number of writes left until queue is full
126
         3 = number of reads available in queue
127
         4 = notify semaphore
128
         5 = number of readers */
129
      arg.val = 0;
130
      /* make sure the creator of the shared memory file also is the creator of the
131
         semaphores...this will ensure that it also creates the message queue */
132
      if (created)
133
        {
134
          saved_errno = errno;
135
          semid = semget (key, 6, IPC_CREAT | IPC_EXCL | mode);
136
          errno = saved_errno;
137
          /* now that we have created the semaphore, we should initialize it */
138
          if (semid != -1)
139
            semctl (semid, 0, SETVAL, arg);
140
        }
141
      else
142
        {
143
          /* if we didn't create the shared memory file but have gotten to here, we want
144
             to ensure we haven't gotten ahead of the creator temporarily so we will
145
             loop until the semaphore exists.  This ensures that the creator will be the
146
             one to create the message queue with the correct mode and we will be blocked
147
             by the open semaphore 0.  We impose a time limit to ensure something terrible
148
             hasn't gone wrong. */
149
          struct timespec tms;
150
          int i;
151
 
152
          tms.tv_sec = 0;
153
          tms.tv_nsec = 10000; /* 10 microseconds */
154
          for (i = 0; i < 100; ++i)
155
            {
156
              if ((semid = semget (key, 6, 0)) != -1)
157
                break;
158
              /* sleep in case we our a higher priority process */
159
              nanosleep (&tms, NULL);
160
            }
161
        }
162
    }
163
 
164
  if (semid != -1)
165
    {
166
      /* acquire main open semaphore if we didn't create it */
167
      if (!created)
168
        {
169
          sb.sem_op = -1;
170
          rc = semop (semid, &sb, 1);
171
        }
172
      else
173
        rc = 0; /* need this to continue below */
174
    }
175
 
176
  if (rc == 0)
177
    {
178
      if (created)
179
        {
180
          /* the creator must get here first so the message queue will be created */
181
          msgqid = msgget (key, IPC_CREAT | mode);
182
          if (msgqid >= 0)
183
            {
184
              /* we have created the message queue so check and set the attributes */
185
              if ((wrbuf = (MSG *)malloc (user_attr->mq_msgsize + sizeof(int))) == NULL ||
186
                  (rdbuf = (MSG *)malloc (user_attr->mq_msgsize + sizeof(int))) == NULL ||
187
                  user_attr == NULL || user_attr->mq_msgsize <= 0 || user_attr->mq_maxmsg <= 0)
188
                {
189
                  /* we're out of space and we created the message queue so we should
190
                     try to remove it */
191
                  msgctl (msgqid, IPC_RMID, NULL);
192
                  msgqid = -1; /* allow clean up to occur below */
193
                  if (wrbuf && rdbuf)
194
                    errno = EINVAL;
195
                  else
196
                    errno = ENOSPC;
197
                }
198
              else /* valid attributes */
199
                {
200
                  write (fd, user_attr, sizeof(struct mq_attr));
201
                  attr->mq_curmsgs = 0;
202
                  attr->mq_flags = oflag & O_NONBLOCK;
203
                  arg.val = 0;
204
                  semctl (semid, 1, SETVAL, arg); /* number of opens starts at 0 */
205
                  semctl (semid, 3, SETVAL, arg); /* number of reads available starts at 0 */
206
                  semctl (semid, 5, SETVAL, arg); /* number of readers starts at 0 */
207
                  arg.val = 1;
208
                  semctl (semid, 4, SETVAL, arg); /* notify semaphore */
209
                  arg.val = user_attr->mq_maxmsg;
210
                  semctl (semid, 2, SETVAL, arg); /* number of writes left starts at mq_maxmsg */
211
                }
212
            }
213
        }
214
      else /* just open it */
215
        {
216
          msgqid = msgget (key, 0);
217
          wrbuf = (MSG *)malloc (attr->mq_msgsize + sizeof(int));
218
          rdbuf = (MSG *)malloc (attr->mq_msgsize + sizeof(int));
219
        }
220
 
221
      /* release semaphore acquired earlier */
222
      sb.sem_op = 1;
223
      semop (semid, &sb, 1);
224
    }
225
 
226
  /* if we get here and we haven't got a message queue id, then we need to clean up
227
     our mess and return failure */
228
  if (msgqid < 0)
229
    {
230
      if (fd >= 0)
231
        close (fd);
232
      if (attr != (struct mq_attr *)MAP_FAILED)
233
        munmap (attr, sizeof(struct mq_attr));
234
      if (created)
235
        {
236
          unlink (real_name);
237
          if (semid != -1)
238
            semctl (semid, 0, IPC_RMID);
239
        }
240
      free (real_name);
241
      free (info);
242
      if (wrbuf)
243
        free (wrbuf);
244
      if (rdbuf)
245
        free (rdbuf);
246
      return (mqd_t)-1;
247
    }
248
 
249
  /* we are successful so register the message queue */
250
 
251
  /* up the count of msg queue opens */
252
  sb.sem_op = 1;
253
  sb.sem_num = 1;
254
  semop (semid, &sb, 1);
255
 
256
  /* success, translate into index into mq_info array */
257
  __lock_acquire(mq_hash_lock);
258
  index = mq_index++;
259
  info->index = index;
260
  info->msgqid = msgqid;
261
  info->name = real_name;
262
  info->semid = semid;
263
  info->fd = fd;
264
  info->oflag = oflag;
265
  info->wrbuf = wrbuf;
266
  info->rdbuf = rdbuf;
267
  info->cleanup_notify = NULL;
268
  info->next = mq_hash[LOCHASH(index)];
269
  info->attr = attr;
270
  mq_hash[LOCHASH(index)] = info;
271
  __lock_release(mq_hash_lock);
272
 
273
  return (mqd_t)index;
274
}
275
 
276
struct libc_mq *
277
__find_mq (mqd_t mq)
278
{
279
  struct libc_mq *ptr;
280
 
281
  __lock_acquire(mq_hash_lock);
282
 
283
  ptr = mq_hash[LOCHASH((int)mq)];
284
 
285
  while (ptr)
286
    {
287
      if (ptr->index == (int)mq)
288
        break;
289
      ptr = ptr->next;
290
    }
291
 
292
  __lock_release(mq_hash_lock);
293
 
294
  return ptr;
295
}
296
 
297
void
298
__cleanup_mq (mqd_t mq)
299
{
300
  struct libc_mq *ptr;
301
  struct libc_mq *prev;
302
  int semid;
303
  struct sembuf sb = {0, 0, 0};
304
 
305
  __lock_acquire(mq_hash_lock);
306
 
307
  ptr = mq_hash[LOCHASH((int)mq)];
308
  prev = NULL;
309
 
310
  while (ptr)
311
    {
312
      if (ptr->index == (int)mq)
313
        break;
314
      prev = ptr;
315
      ptr = ptr->next;
316
    }
317
 
318
  if (ptr != NULL)
319
    {
320
      if (ptr->cleanup_notify != NULL)
321
        ptr->cleanup_notify (ptr);
322
      if (prev != NULL)
323
        prev->next = ptr->next;
324
      else
325
        mq_hash[LOCHASH((int)mq)] = NULL;
326
      munmap (ptr->attr, sizeof(struct mq_attr));
327
      close (ptr->fd);
328
      free (ptr->name);
329
      free (ptr->wrbuf);
330
      free (ptr->rdbuf);
331
      semid = ptr->semid;
332
      free (ptr);
333
      /* lower the count of msg queue opens */
334
      sb.sem_op = -1;
335
      sb.sem_num = 1;
336
      sb.sem_flg = IPC_NOWAIT;
337
      semop (semid, &sb, 1);
338
    }
339
 
340
  __lock_release(mq_hash_lock);
341
}
342
 
343
 
344
 
345
 
346
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.