]>
sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/posix_ipc.cc
1 /* posix_ipc.cc: POSIX IPC API for Cygwin.
3 Copyright 2007 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
23 #include <sys/param.h>
31 #include <semaphore.h>
37 const char *description
;
39 { "/dev/shm", CYG_MAX_PATH
- 10, "POSIX shared memory object" },
40 { "/dev/mqueue", CYG_MAX_PATH
- 13, "POSIX message queue" },
41 { "/dev/shm", CYG_MAX_PATH
- 14, "POSIX semaphore" }
52 check_path (char *res_name
, ipc_type_t type
, const char *name
)
54 /* Note that we require the existance of the apprpriate /dev subdirectories
55 for POSIX IPC object support, similar to Linux (which supports the
56 directories, but doesn't require to mount them). We don't create
57 these directory here, that's the task of the installer. But we check
58 for existance and give ample warning. */
59 path_conv
path (ipc_names
[type
].prefix
, PC_SYM_NOFOLLOW
);
60 if (path
.error
|| !path
.exists () || !path
.isdir ())
63 "Warning: '%s' does not exists or is not a directory.\n\n"
64 "%ss require the existance of this directory.\n"
65 "Create the directory '%s' and set the permissions to 01777.\n"
66 "For instance on the command line: mkdir -m 01777 %s\n",
67 ipc_names
[type
].prefix
, ipc_names
[type
].description
,
68 ipc_names
[type
].prefix
, ipc_names
[type
].prefix
);
72 /* Name must start with a single slash. */
73 if (!name
|| name
[0] != '/' || name
[1] == '/' || !name
[1])
75 debug_printf ("Invalid %s name '%s'", ipc_names
[type
].description
, name
);
79 if (strlen (name
) > ipc_names
[type
].max_len
)
81 debug_printf ("%s name '%s' too long", ipc_names
[type
].description
, name
);
82 set_errno (ENAMETOOLONG
);
85 __small_sprintf (res_name
, "%s/%s%s", ipc_names
[type
].prefix
,
86 type
== semaphore
? "sem." : "",
92 ipc_mutex_init (HANDLE
*pmtx
, const char *name
)
94 char buf
[CYG_MAX_PATH
];
95 __small_sprintf (buf
, "%scyg_pmtx/%s", cygheap
->shared_prefix
, name
);
96 *pmtx
= CreateMutex (&sec_all
, FALSE
, buf
);
98 debug_printf ("failed: %E\n");
99 return *pmtx
? 0 : geterrno_from_win_error ();
103 ipc_mutex_lock (HANDLE mtx
)
105 HANDLE h
[2] = { mtx
, signal_arrived
};
107 switch (WaitForMultipleObjects (2, h
, FALSE
, INFINITE
))
110 case WAIT_ABANDONED_0
:
112 case WAIT_OBJECT_0
+ 1:
118 return geterrno_from_win_error ();
122 ipc_mutex_unlock (HANDLE mtx
)
124 return ReleaseMutex (mtx
) ? 0 : geterrno_from_win_error ();
128 ipc_mutex_close (HANDLE mtx
)
130 return CloseHandle (mtx
) ? 0 : geterrno_from_win_error ();
134 ipc_cond_init (HANDLE
*pevt
, const char *name
)
136 char buf
[CYG_MAX_PATH
];
137 __small_sprintf (buf
, "%scyg_pevt/%s", cygheap
->shared_prefix
, name
);
138 *pevt
= CreateEvent (&sec_all
, TRUE
, FALSE
, buf
);
140 debug_printf ("failed: %E\n");
141 return *pevt
? 0 : geterrno_from_win_error ();
145 ipc_cond_timedwait (HANDLE evt
, HANDLE mtx
, const struct timespec
*abstime
)
149 HANDLE h
[2] = { mtx
, evt
};
153 else if (abstime
->tv_sec
< 0
154 || abstime
->tv_nsec
< 0
155 || abstime
->tv_nsec
> 999999999)
159 gettimeofday (&tv
, NULL
);
160 /* Check for immediate timeout. */
161 if (tv
.tv_sec
> abstime
->tv_sec
162 || (tv
.tv_sec
== abstime
->tv_sec
163 && tv
.tv_usec
> abstime
->tv_nsec
/ 1000))
165 timeout
= (abstime
->tv_sec
- tv
.tv_sec
) * 1000;
166 timeout
+= (abstime
->tv_nsec
/ 1000 - tv
.tv_usec
) / 1000;
168 if (ipc_mutex_unlock (mtx
))
170 switch (WaitForMultipleObjects (2, h
, TRUE
, timeout
))
173 case WAIT_ABANDONED_0
:
177 ipc_mutex_lock (mtx
);
182 return geterrno_from_win_error ();
186 ipc_cond_signal (HANDLE evt
)
188 return SetEvent (evt
) ? 0 : geterrno_from_win_error ();
192 ipc_cond_close (HANDLE evt
)
194 return CloseHandle (evt
) ? 0 : geterrno_from_win_error ();
202 ipc_flock () { memset (&fl
, 0, sizeof fl
); }
204 int lock (int fd
, size_t size
)
207 fl
.l_whence
= SEEK_SET
;
210 return fcntl (fd
, F_SETLKW
, &fl
);
217 return fcntl (fd
, F_SETLKW
, &fl
);
221 /* POSIX shared memory object implementation. */
224 shm_open (const char *name
, int oflag
, mode_t mode
)
226 char shmname
[CYG_MAX_PATH
];
228 if (!check_path (shmname
, shmem
, name
))
231 /* Check for valid flags. */
232 if (((oflag
& O_ACCMODE
) != O_RDONLY
&& (oflag
& O_ACCMODE
) != O_RDWR
)
233 || (oflag
& ~(O_ACCMODE
| O_CREAT
| O_EXCL
| O_TRUNC
)))
235 debug_printf ("Invalid oflag 0%o", oflag
);
240 return open (shmname
, oflag
, mode
& 0777);
244 shm_unlink (const char *name
)
246 char shmname
[CYG_MAX_PATH
];
248 if (!check_path (shmname
, shmem
, name
))
251 return unlink (shmname
);
254 /* The POSIX message queue implementation is based on W. Richard STEVENS
255 implementation, just tweaked for Cygwin. The main change is
256 the usage of Windows mutexes and events instead of using the pthread
257 synchronization objects. The pathname is massaged so that the
258 files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
259 are implemented additionally. */
263 struct mq_attr mqh_attr
; /* the queue's attributes */
264 long mqh_head
; /* index of first message */
265 long mqh_free
; /* index of first free message */
266 long mqh_nwait
; /* #threads blocked in mq_receive() */
267 pid_t mqh_pid
; /* nonzero PID if mqh_event set */
268 char mqh_uname
[36]; /* unique name used to identify synchronization
269 objects connected to this queue */
270 struct sigevent mqh_event
; /* for mq_notify() */
275 long msg_next
; /* index of next on linked list */
276 ssize_t msg_len
; /* actual length */
277 unsigned int msg_prio
; /* priority */
282 struct mq_hdr
*mqi_hdr
; /* start of mmap'ed region */
283 unsigned long mqi_magic
; /* magic number if open */
284 int mqi_flags
; /* flags for this process */
285 HANDLE mqi_lock
; /* mutex lock */
286 HANDLE mqi_wait
; /* and condition variable */
289 #define MQI_MAGIC 0x98765432UL
291 #define MSGSIZE(i) roundup((i), sizeof(long))
293 #define MAX_TRIES 10 /* for waiting for initialization */
295 struct mq_attr defattr
= { 0, 10, 8192, 0 }; /* Linux defaults. */
297 extern "C" _off64_t
lseek64 (int, _off64_t
, int);
298 extern "C" void *mmap64 (void *, size_t, int, int, int, _off64_t
);
301 mq_open (const char *name
, int oflag
, ...)
303 int i
, fd
, nonblock
, created
;
305 _off64_t filesize
= 0;
309 struct __stat64 statbuff
;
310 struct mq_hdr
*mqhdr
;
311 struct msg_hdr
*msghdr
;
312 struct mq_attr
*attr
;
313 struct mq_info
*mqinfo
;
315 char mqname
[CYG_MAX_PATH
];
317 if (!check_path (mqname
, mqueue
, name
))
321 if (efault
.faulted (EFAULT
))
324 oflag
&= (O_CREAT
| O_EXCL
| O_NONBLOCK
);
326 nonblock
= oflag
& O_NONBLOCK
;
327 oflag
&= ~O_NONBLOCK
;
328 mptr
= (int8_t *) MAP_FAILED
;
334 va_start (ap
, oflag
); /* init ap to final named argument */
335 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
336 attr
= va_arg (ap
, struct mq_attr
*);
339 /* Open and specify O_EXCL and user-execute */
340 fd
= open (mqname
, oflag
| O_EXCL
| O_RDWR
, mode
| S_IXUSR
);
343 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
344 goto exists
; /* already exists, OK */
348 /* First one to create the file initializes it */
351 else if (attr
->mq_maxmsg
<= 0 || attr
->mq_msgsize
<= 0)
356 /* Calculate and set the file size */
357 msgsize
= MSGSIZE (attr
->mq_msgsize
);
358 filesize
= sizeof (struct mq_hdr
)
359 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
360 if (lseek64 (fd
, filesize
- 1, SEEK_SET
) == -1)
362 if (write (fd
, "", 1) == -1)
365 /* Memory map the file */
366 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
368 if (mptr
== (int8_t *) MAP_FAILED
)
371 /* Allocate one mq_info{} for the queue */
372 if (!(mqinfo
= (struct mq_info
*) malloc (sizeof (struct mq_info
))))
374 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
375 mqinfo
->mqi_magic
= MQI_MAGIC
;
376 mqinfo
->mqi_flags
= nonblock
;
378 /* Initialize header at beginning of file */
379 /* Create free list with all messages on it */
380 mqhdr
->mqh_attr
.mq_flags
= 0;
381 mqhdr
->mqh_attr
.mq_maxmsg
= attr
->mq_maxmsg
;
382 mqhdr
->mqh_attr
.mq_msgsize
= attr
->mq_msgsize
;
383 mqhdr
->mqh_attr
.mq_curmsgs
= 0;
384 mqhdr
->mqh_nwait
= 0;
386 if (!AllocateLocallyUniqueId (&luid
))
391 __small_sprintf (mqhdr
->mqh_uname
, "cyg%016X%08x%08x",
392 hash_path_name (0,mqname
),
393 luid
.HighPart
, luid
.LowPart
);
395 index
= sizeof (struct mq_hdr
);
396 mqhdr
->mqh_free
= index
;
397 for (i
= 0; i
< attr
->mq_maxmsg
- 1; i
++)
399 msghdr
= (struct msg_hdr
*) &mptr
[index
];
400 index
+= sizeof (struct msg_hdr
) + msgsize
;
401 msghdr
->msg_next
= index
;
403 msghdr
= (struct msg_hdr
*) &mptr
[index
];
404 msghdr
->msg_next
= 0; /* end of free list */
406 /* Initialize mutex & condition variable */
407 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
411 i
= ipc_cond_init (&mqinfo
->mqi_wait
, mqhdr
->mqh_uname
);
415 /* Initialization complete, turn off user-execute bit */
416 if (fchmod (fd
, mode
) == -1)
419 return ((mqd_t
) mqinfo
);
423 /* Open the file then memory map */
424 if ((fd
= open (mqname
, O_RDWR
)) < 0)
426 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
430 /* Make certain initialization is complete */
431 for (i
= 0; i
< MAX_TRIES
; i
++)
433 if (stat64 (mqname
, &statbuff
) == -1)
435 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
442 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
448 set_errno (ETIMEDOUT
);
452 filesize
= statbuff
.st_size
;
453 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
455 if (mptr
== (int8_t *) MAP_FAILED
)
459 /* Allocate one mq_info{} for each open */
460 if (!(mqinfo
= (struct mq_info
*) malloc (sizeof (struct mq_info
))))
462 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
463 mqinfo
->mqi_magic
= MQI_MAGIC
;
464 mqinfo
->mqi_flags
= nonblock
;
466 /* Initialize mutex & condition variable */
467 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
471 i
= ipc_cond_init (&mqinfo
->mqi_wait
, mqhdr
->mqh_uname
);
475 return (mqd_t
) mqinfo
;
480 /* Don't let following function calls change errno */
485 if (mptr
!= (int8_t *) MAP_FAILED
)
486 munmap((void *) mptr
, (size_t) filesize
);
494 mq_getattr (mqd_t mqd
, struct mq_attr
*mqstat
)
497 struct mq_hdr
*mqhdr
;
498 struct mq_attr
*attr
;
499 struct mq_info
*mqinfo
;
502 if (efault
.faulted (EBADF
))
505 mqinfo
= (struct mq_info
*) mqd
;
506 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
511 mqhdr
= mqinfo
->mqi_hdr
;
512 attr
= &mqhdr
->mqh_attr
;
513 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
518 mqstat
->mq_flags
= mqinfo
->mqi_flags
; /* per-open */
519 mqstat
->mq_maxmsg
= attr
->mq_maxmsg
; /* remaining three per-queue */
520 mqstat
->mq_msgsize
= attr
->mq_msgsize
;
521 mqstat
->mq_curmsgs
= attr
->mq_curmsgs
;
523 ipc_mutex_unlock (mqinfo
->mqi_lock
);
528 mq_setattr (mqd_t mqd
, const struct mq_attr
*mqstat
, struct mq_attr
*omqstat
)
531 struct mq_hdr
*mqhdr
;
532 struct mq_attr
*attr
;
533 struct mq_info
*mqinfo
;
536 if (efault
.faulted (EBADF
))
539 mqinfo
= (struct mq_info
*) mqd
;
540 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
545 mqhdr
= mqinfo
->mqi_hdr
;
546 attr
= &mqhdr
->mqh_attr
;
547 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
555 omqstat
->mq_flags
= mqinfo
->mqi_flags
; /* previous attributes */
556 omqstat
->mq_maxmsg
= attr
->mq_maxmsg
;
557 omqstat
->mq_msgsize
= attr
->mq_msgsize
;
558 omqstat
->mq_curmsgs
= attr
->mq_curmsgs
; /* and current status */
561 if (mqstat
->mq_flags
& O_NONBLOCK
)
562 mqinfo
->mqi_flags
|= O_NONBLOCK
;
564 mqinfo
->mqi_flags
&= ~O_NONBLOCK
;
566 ipc_mutex_unlock (mqinfo
->mqi_lock
);
571 mq_notify (mqd_t mqd
, const struct sigevent
*notification
)
575 struct mq_hdr
*mqhdr
;
576 struct mq_info
*mqinfo
;
579 if (efault
.faulted (EBADF
))
582 mqinfo
= (struct mq_info
*) mqd
;
583 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
588 mqhdr
= mqinfo
->mqi_hdr
;
589 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
598 if (mqhdr
->mqh_pid
== pid
)
599 mqhdr
->mqh_pid
= 0; /* unregister calling process */
603 if (mqhdr
->mqh_pid
!= 0)
605 if (kill (mqhdr
->mqh_pid
, 0) != -1 || errno
!= ESRCH
)
608 ipc_mutex_unlock (mqinfo
->mqi_lock
);
612 mqhdr
->mqh_pid
= pid
;
613 mqhdr
->mqh_event
= *notification
;
615 ipc_mutex_unlock (mqinfo
->mqi_lock
);
620 _mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
621 const struct timespec
*abstime
)
624 long index
, freeindex
;
626 struct sigevent
*sigev
;
627 struct mq_hdr
*mqhdr
;
628 struct mq_attr
*attr
;
629 struct msg_hdr
*msghdr
, *nmsghdr
, *pmsghdr
;
630 struct mq_info
*mqinfo
;
633 if (efault
.faulted (EBADF
))
636 mqinfo
= (struct mq_info
*) mqd
;
637 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
642 if (prio
> MQ_PRIO_MAX
)
648 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
649 mptr
= (int8_t *) mqhdr
; /* byte pointer */
650 attr
= &mqhdr
->mqh_attr
;
651 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
657 if (len
> (size_t) attr
->mq_msgsize
)
659 set_errno (EMSGSIZE
);
662 if (attr
->mq_curmsgs
== 0)
664 if (mqhdr
->mqh_pid
!= 0 && mqhdr
->mqh_nwait
== 0)
666 sigev
= &mqhdr
->mqh_event
;
667 if (sigev
->sigev_notify
== SIGEV_SIGNAL
)
668 sigqueue (mqhdr
->mqh_pid
, sigev
->sigev_signo
, sigev
->sigev_value
);
669 mqhdr
->mqh_pid
= 0; /* unregister */
672 else if (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
675 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
680 /* Wait for room for one message on the queue */
681 while (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
682 ipc_cond_timedwait (mqinfo
->mqi_wait
, mqinfo
->mqi_lock
, abstime
);
685 /* nmsghdr will point to new message */
686 if ((freeindex
= mqhdr
->mqh_free
) == 0)
687 api_fatal ("mq_send: curmsgs = %ld; free = 0", attr
->mq_curmsgs
);
689 nmsghdr
= (struct msg_hdr
*) &mptr
[freeindex
];
690 nmsghdr
->msg_prio
= prio
;
691 nmsghdr
->msg_len
= len
;
692 memcpy (nmsghdr
+ 1, ptr
, len
); /* copy message from caller */
693 mqhdr
->mqh_free
= nmsghdr
->msg_next
; /* new freelist head */
695 /* Find right place for message in linked list */
696 index
= mqhdr
->mqh_head
;
697 pmsghdr
= (struct msg_hdr
*) &(mqhdr
->mqh_head
);
700 msghdr
= (struct msg_hdr
*) &mptr
[index
];
701 if (prio
> msghdr
->msg_prio
)
703 nmsghdr
->msg_next
= index
;
704 pmsghdr
->msg_next
= freeindex
;
707 index
= msghdr
->msg_next
;
712 /* Queue was empty or new goes at end of list */
713 pmsghdr
->msg_next
= freeindex
;
714 nmsghdr
->msg_next
= 0;
716 /* Wake up anyone blocked in mq_receive waiting for a message */
717 if (attr
->mq_curmsgs
== 0)
718 ipc_cond_signal (mqinfo
->mqi_wait
);
721 ipc_mutex_unlock (mqinfo
->mqi_lock
);
725 ipc_mutex_unlock (mqinfo
->mqi_lock
);
730 mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
)
732 return _mq_send (mqd
, ptr
, len
, prio
, NULL
);
736 mq_timedsend (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
737 const struct timespec
*abstime
)
739 return _mq_send (mqd
, ptr
, len
, prio
, abstime
);
743 _mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
744 const struct timespec
*abstime
)
750 struct mq_hdr
*mqhdr
;
751 struct mq_attr
*attr
;
752 struct msg_hdr
*msghdr
;
753 struct mq_info
*mqinfo
;
756 if (efault
.faulted (EBADF
))
759 mqinfo
= (struct mq_info
*) mqd
;
760 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
765 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
766 mptr
= (int8_t *) mqhdr
; /* byte pointer */
767 attr
= &mqhdr
->mqh_attr
;
768 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
774 if (maxlen
< (size_t) attr
->mq_msgsize
)
776 set_errno (EMSGSIZE
);
779 if (attr
->mq_curmsgs
== 0) /* queue is empty */
781 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
786 /* Wait for a message to be placed onto queue */
788 while (attr
->mq_curmsgs
== 0)
789 ipc_cond_timedwait (mqinfo
->mqi_wait
, mqinfo
->mqi_lock
, abstime
);
793 if ((index
= mqhdr
->mqh_head
) == 0)
794 api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr
->mq_curmsgs
);
796 msghdr
= (struct msg_hdr
*) &mptr
[index
];
797 mqhdr
->mqh_head
= msghdr
->msg_next
; /* new head of list */
798 len
= msghdr
->msg_len
;
799 memcpy(ptr
, msghdr
+ 1, len
); /* copy the message itself */
801 *priop
= msghdr
->msg_prio
;
803 /* Just-read message goes to front of free list */
804 msghdr
->msg_next
= mqhdr
->mqh_free
;
805 mqhdr
->mqh_free
= index
;
807 /* Wake up anyone blocked in mq_send waiting for room */
808 if (attr
->mq_curmsgs
== attr
->mq_maxmsg
)
809 ipc_cond_signal (mqinfo
->mqi_wait
);
812 ipc_mutex_unlock (mqinfo
->mqi_lock
);
816 ipc_mutex_unlock (mqinfo
->mqi_lock
);
821 mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
)
823 return _mq_receive (mqd
, ptr
, maxlen
, priop
, NULL
);
827 mq_timedreceive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
828 const struct timespec
*abstime
)
830 return _mq_receive (mqd
, ptr
, maxlen
, priop
, abstime
);
836 long msgsize
, filesize
;
837 struct mq_hdr
*mqhdr
;
838 struct mq_attr
*attr
;
839 struct mq_info
*mqinfo
;
842 if (efault
.faulted (EBADF
))
845 mqinfo
= (struct mq_info
*) mqd
;
846 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
851 mqhdr
= mqinfo
->mqi_hdr
;
852 attr
= &mqhdr
->mqh_attr
;
854 if (mq_notify (mqd
, NULL
)) /* unregister calling process */
857 msgsize
= MSGSIZE (attr
->mq_msgsize
);
858 filesize
= sizeof (struct mq_hdr
)
859 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
860 if (munmap (mqinfo
->mqi_hdr
, filesize
) == -1)
863 mqinfo
->mqi_magic
= 0; /* just in case */
864 ipc_cond_close (mqinfo
->mqi_wait
);
865 ipc_mutex_close (mqinfo
->mqi_lock
);
871 mq_unlink (const char *name
)
873 char mqname
[CYG_MAX_PATH
];
875 if (!check_path (mqname
, mqueue
, name
))
877 if (unlink (mqname
) == -1)
882 /* POSIX named semaphore implementation. Loosely based on Richard W. STEPHENS
883 implementation as far as sem_open is concerned, but under the hood using
884 the already existing semaphore class in thread.cc. Using a file backed
885 solution allows to implement kernel persistent named semaphores. */
890 unsigned long long hash
;
895 sem_open (const char *name
, int oflag
, ...)
900 unsigned int value
= 0;
901 struct __stat64 statbuff
;
902 sem_t
*sem
= SEM_FAILED
;
904 char semname
[CYG_MAX_PATH
];
905 bool wasopen
= false;
908 if (!check_path (semname
, semaphore
, name
))
912 if (efault
.faulted (EFAULT
))
916 oflag
&= (O_CREAT
| O_EXCL
);
921 va_start (ap
, oflag
); /* init ap to final named argument */
922 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
923 value
= va_arg (ap
, unsigned int);
926 /* Open and specify O_EXCL and user-execute */
927 fd
= open (semname
, oflag
| O_EXCL
| O_RDWR
, mode
| S_IXUSR
);
930 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
931 goto exists
; /* already exists, OK */
935 /* First one to create the file initializes it. */
936 if (!AllocateLocallyUniqueId (&sf
.luid
))
942 sf
.hash
= hash_path_name (0, semname
);
943 if (write (fd
, &sf
, sizeof sf
) != sizeof sf
)
945 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, value
, wasopen
);
946 if (sem
== SEM_FAILED
)
948 /* Initialization complete, turn off user-execute bit */
949 if (fchmod (fd
, mode
) == -1)
951 /* Don't close (fd); */
956 /* Open the file and fetch the semaphore name. */
957 if ((fd
= open (semname
, O_RDWR
)) < 0)
959 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
963 /* Make certain initialization is complete */
964 for (i
= 0; i
< MAX_TRIES
; i
++)
966 if (stat64 (semname
, &statbuff
) == -1)
968 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
975 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
981 set_errno (ETIMEDOUT
);
984 if (file
.lock (fd
, sizeof sf
))
986 if (read (fd
, &sf
, sizeof sf
) != sizeof sf
)
988 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, sf
.value
, wasopen
);
990 if (sem
== SEM_FAILED
)
992 /* If wasopen is set, the semaphore was already opened and we already have
993 an open file descriptor pointing to the file. This means, we have to
994 close the file descriptor created in this call. It won't be stored
1001 /* Don't let following function calls change errno */
1007 if (sem
!= SEM_FAILED
)
1008 semaphore::close (sem
);
1014 _sem_close (sem_t
*sem
, bool do_close
)
1020 if (semaphore::getinternal (sem
, &fd
, &sf
.hash
, &sf
.luid
, &sf
.value
) == -1)
1022 if (!file
.lock (fd
, sizeof sf
)
1023 && lseek64 (fd
, 0LL, SEEK_SET
) != (_off64_t
) -1
1024 && write (fd
, &sf
, sizeof sf
) == sizeof sf
)
1025 ret
= do_close
? semaphore::close (sem
) : 0;
1027 /* Don't let following function calls change errno */
1036 sem_close (sem_t
*sem
)
1038 return _sem_close (sem
, true);
1042 sem_unlink (const char *name
)
1044 char semname
[CYG_MAX_PATH
];
1046 if (!check_path (semname
, semaphore
, name
))
1048 if (unlink (semname
) == -1)
This page took 0.083793 seconds and 6 git commands to generate.