]>
sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/posix_ipc.cc
300a3f46ffd9159fb816139766b50d1260abfb5d
1 /* posix_ipc.cc: POSIX IPC API for Cygwin.
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 #include "shared_info.h"
21 #include <sys/param.h>
25 #include <semaphore.h>
27 extern "C" int ftruncate64 (int fd
, off_t length
);
29 /* The prefix_len is the length of the path prefix including trailing "/"
30 (or "/sem." for semaphores) as well as the trailing NUL. */
34 const size_t prefix_len
;
35 const char *description
;
37 { "/dev/shm", 10, "POSIX shared memory object" },
38 { "/dev/mqueue", 13, "POSIX message queue" },
39 { "/dev/shm", 14, "POSIX semaphore" }
50 check_path (char *res_name
, ipc_type_t type
, const char *name
, size_t len
)
52 /* Note that we require the existance of the appropriate /dev subdirectories
53 for POSIX IPC object support, similar to Linux (which supports the
54 directories, but doesn't require to mount them). We don't create
55 these directory here, that's the task of the installer. But we check
56 for existance and give ample warning. */
57 path_conv
path (ipc_names
[type
].prefix
, PC_SYM_NOFOLLOW
);
58 if (path
.error
|| !path
.exists () || !path
.isdir ())
61 "Warning: '%s' does not exists or is not a directory.\n\n"
62 "%ss require the existance of this directory.\n"
63 "Create the directory '%s' and set the permissions to 01777.\n"
64 "For instance on the command line: mkdir -m 01777 %s\n",
65 ipc_names
[type
].prefix
, ipc_names
[type
].description
,
66 ipc_names
[type
].prefix
, ipc_names
[type
].prefix
);
70 /* Apart from handling backslash like slash, the naming rules are identical
71 to Linux, including the names and requirements for subdirectories, if
72 the name contains further slashes. */
73 /* Name must not be empty and has to start with a slash (or backslash) */
74 if (!name
|| !strchr ("/\\", name
[0]))
76 debug_printf ("Invalid %s name '%s'", ipc_names
[type
].description
, name
);
80 /* Name must not consist of just a single slash (or backslash) */
83 debug_printf ("Invalid %s name '%s'", ipc_names
[type
].description
, name
);
87 /* Name must not contain slashes after the leading one */
88 if (strpbrk (name
+ 1, "/\\"))
90 debug_printf ("Invalid %s name '%s'", ipc_names
[type
].description
, name
);
94 /* Length must be less than or equal to NAME_MAX, or NAME_MAX - 4 in
95 case of semaphores, due to the leading "sem." prefix */
96 if (len
> NAME_MAX
- (type
== semaphore
? strlen ("sem.") : 0))
98 debug_printf ("%s name '%s' too long", ipc_names
[type
].description
, name
);
99 set_errno (ENAMETOOLONG
);
102 __small_sprintf (res_name
, "%s/%s%s", ipc_names
[type
].prefix
,
103 type
== semaphore
? "sem." : "",
109 ipc_mutex_lock (HANDLE mtx
, bool eintr
)
111 switch (cygwait (mtx
, cw_infinite
, cw_cancel
| cw_cancel_self
112 | (eintr
? cw_sig_eintr
: cw_sig_restart
)))
115 case WAIT_ABANDONED_0
:
123 return geterrno_from_win_error ();
127 ipc_mutex_unlock (HANDLE mtx
)
129 return ReleaseMutex (mtx
) ? 0 : geterrno_from_win_error ();
133 ipc_cond_timedwait (HANDLE evt
, HANDLE mtx
, const struct timespec
*abstime
)
135 HANDLE w4
[4] = { evt
, };
140 wait_signal_arrived
here (w4
[1]);
141 if ((w4
[cnt
] = pthread::get_cancel_event ()) != NULL
)
145 if (!valid_timespec (*abstime
))
148 /* If a timeout is set, we create a waitable timer to wait for.
149 This is the easiest way to handle the absolute timeout value, given
150 that NtSetTimer also takes absolute times and given the double
151 dependency on evt *and* mtx, which requires to call WFMO twice. */
153 LARGE_INTEGER duetime
;
156 status
= NtCreateTimer (&w4
[timer_idx
], TIMER_ALL_ACCESS
, NULL
,
158 if (!NT_SUCCESS (status
))
159 return geterrno_from_nt_status (status
);
160 timespec_to_filetime (abstime
, &duetime
);
161 status
= NtSetTimer (w4
[timer_idx
], &duetime
, NULL
, NULL
, FALSE
, 0, NULL
);
162 if (!NT_SUCCESS (status
))
164 NtClose (w4
[timer_idx
]);
165 return geterrno_from_nt_status (status
);
169 if ((ret
= ipc_mutex_unlock (mtx
)) != 0)
171 /* Everything's set up, so now wait for the event to be signalled. */
173 switch (WaitForMultipleObjects (cnt
, w4
, FALSE
, INFINITE
))
177 case WAIT_OBJECT_0
+ 1:
178 if (_my_tls
.call_signal_handler ())
182 case WAIT_OBJECT_0
+ 2:
184 pthread::static_cancel_self ();
186 case WAIT_OBJECT_0
+ 3:
190 ret
= geterrno_from_win_error ();
195 /* At this point we need to lock the mutex. The wait is practically
196 the same as before, just that we now wait on the mutex instead of the
200 switch (WaitForMultipleObjects (cnt
, w4
, FALSE
, INFINITE
))
203 case WAIT_ABANDONED_0
:
205 case WAIT_OBJECT_0
+ 1:
206 if (_my_tls
.call_signal_handler ())
210 case WAIT_OBJECT_0
+ 2:
212 pthread_testcancel ();
214 case WAIT_OBJECT_0
+ 3:
218 ret
= geterrno_from_win_error ();
224 if (ret
!= ETIMEDOUT
)
225 NtCancelTimer (w4
[timer_idx
], NULL
);
226 NtClose (w4
[timer_idx
]);
232 ipc_cond_signal (HANDLE evt
)
242 ipc_flock () { memset (&fl
, 0, sizeof fl
); }
244 int lock (int fd
, size_t size
)
247 fl
.l_whence
= SEEK_SET
;
250 return fcntl64 (fd
, F_SETLKW
, &fl
);
257 return fcntl64 (fd
, F_SETLKW
, &fl
);
261 /* POSIX shared memory object implementation. */
264 shm_open (const char *name
, int oflag
, mode_t mode
)
266 size_t len
= strlen (name
);
267 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
269 if (!check_path (shmname
, shmem
, name
, len
))
272 /* Check for valid flags. */
273 if (((oflag
& O_ACCMODE
) != O_RDONLY
&& (oflag
& O_ACCMODE
) != O_RDWR
)
274 || (oflag
& ~(O_ACCMODE
| O_CREAT
| O_EXCL
| O_TRUNC
)))
276 debug_printf ("Invalid oflag 0%o", oflag
);
281 return open (shmname
, oflag
| O_CLOEXEC
, mode
& 0777);
285 shm_unlink (const char *name
)
287 size_t len
= strlen (name
);
288 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
290 if (!check_path (shmname
, shmem
, name
, len
))
293 return unlink (shmname
);
296 /* The POSIX message queue implementation is based on W. Richard STEVENS
297 implementation, just tweaked for Cygwin. The main change is
298 the usage of Windows mutexes and events instead of using the pthread
299 synchronization objects. The pathname is massaged so that the
300 files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
301 are implemented additionally. */
303 #pragma pack (push, 4)
306 int32_t msg_next
; /* index of next on linked list */
307 int32_t msg_len
; /* actual length */
308 unsigned int msg_prio
; /* priority */
312 #define MSGSIZE(i) roundup((i), sizeof(long))
314 #define MAX_TRIES 10 /* for waiting for initialization */
316 struct mq_attr defattr
= { 0, 10, 8192, 0 }; /* Linux defaults. */
318 extern "C" off_t
lseek64 (int, off_t
, int);
319 extern "C" void *mmap64 (void *, size_t, int, int, int, off_t
);
322 mq_open (const char *name
, int oflag
, ...)
324 int i
, fd
= -1, nonblock
, created
= 0;
329 fhandler_mqueue
*fh
= NULL
;
330 struct stat statbuff
;
332 struct mq_hdr
*mqhdr
;
333 struct msg_hdr
*msghdr
;
334 struct mq_attr
*attr
;
335 struct mq_info
*mqinfo
= NULL
;
337 size_t len
= strlen (name
);
338 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
340 if (!check_path (mqname
, mqueue
, name
, len
))
345 oflag
&= (O_CREAT
| O_EXCL
| O_NONBLOCK
);
346 nonblock
= oflag
& O_NONBLOCK
;
347 oflag
&= ~O_NONBLOCK
;
352 va_start (ap
, oflag
); /* init ap to final named argument */
353 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
354 attr
= va_arg (ap
, struct mq_attr
*);
357 /* Open and specify O_EXCL and user-execute */
358 fd
= open (mqname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
,
362 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
363 goto exists
; /* already exists, OK */
367 /* First one to create the file initializes it */
370 /* Check minimum and maximum values. The max values are pretty much
371 arbitrary, taken from the linux mq_overview man page. However,
372 these max values make sure that the internal mq_fattr structure
373 can use 32 bit types. */
374 else if (attr
->mq_maxmsg
<= 0 || attr
->mq_maxmsg
> 32768
375 || attr
->mq_msgsize
<= 0 || attr
->mq_msgsize
> 1048576)
380 /* Calculate and set the file size */
381 msgsize
= MSGSIZE (attr
->mq_msgsize
);
382 filesize
= sizeof (struct mq_hdr
)
383 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
384 if (ftruncate64 (fd
, filesize
) == -1)
387 /* Create file descriptor for mqueue */
392 fh
= (fhandler_mqueue
*) build_fh_dev (*mqueue_dev
, name
);
396 mqinfo
= fh
->mqinfo_create ((HANDLE
) _get_osfhandle (fd
), filesize
,
401 /* Initialize header at beginning of file */
402 /* Create free list with all messages on it */
403 mptr
= (int8_t *) mqinfo
->mqi_hdr
;
404 mqhdr
= mqinfo
->mqi_hdr
;
405 mqhdr
->mqh_attr
.mq_flags
= 0;
406 mqhdr
->mqh_attr
.mq_maxmsg
= attr
->mq_maxmsg
;
407 mqhdr
->mqh_attr
.mq_msgsize
= attr
->mq_msgsize
;
408 mqhdr
->mqh_attr
.mq_curmsgs
= 0;
409 mqhdr
->mqh_nwait
= 0;
412 mqhdr
->mqh_magic
= MQI_MAGIC
;
413 index
= sizeof (struct mq_hdr
);
414 mqhdr
->mqh_free
= index
;
415 for (i
= 0; i
< attr
->mq_maxmsg
- 1; i
++)
417 msghdr
= (struct msg_hdr
*) &mptr
[index
];
418 index
+= sizeof (struct msg_hdr
) + msgsize
;
419 msghdr
->msg_next
= index
;
421 msghdr
= (struct msg_hdr
*) &mptr
[index
];
422 msghdr
->msg_next
= 0; /* end of free list */
424 /* Initialization complete, turn off user-execute bit */
425 if (fchmod (fd
, mode
) == -1)
433 /* Open the file then memory map */
434 if ((fd
= open (mqname
, O_RDWR
| O_CLOEXEC
)) < 0)
436 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
440 /* Make certain initialization is complete */
441 for (i
= 0; i
< MAX_TRIES
; i
++)
443 if (stat64 (mqname
, &statbuff
) == -1)
445 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
453 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
459 set_errno (ETIMEDOUT
);
463 /* Create file descriptor for mqueue */
468 fh
= (fhandler_mqueue
*) build_fh_dev (*mqueue_dev
, name
);
472 mqinfo
= fh
->mqinfo_open ((HANDLE
) _get_osfhandle (fd
), statbuff
.st_size
,
473 statbuff
.st_mode
, nonblock
);
483 /* Don't let following function calls change errno */
497 static struct mq_info
*
498 get_mqinfo (cygheap_fdget
&fd
)
502 fhandler_mqueue
*fh
= fd
->is_mqueue ();
504 return fh
->mqinfo ();
511 mq_getattr (mqd_t mqd
, struct mq_attr
*mqstat
)
514 struct mq_hdr
*mqhdr
;
515 struct mq_fattr
*attr
;
516 struct mq_info
*mqinfo
;
520 cygheap_fdget
fd ((int) mqd
, true);
521 mqinfo
= get_mqinfo (fd
);
522 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
527 mqhdr
= mqinfo
->mqi_hdr
;
528 attr
= &mqhdr
->mqh_attr
;
529 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, false)) != 0)
534 mqstat
->mq_flags
= mqinfo
->mqi_flags
; /* per-open */
535 mqstat
->mq_maxmsg
= attr
->mq_maxmsg
; /* remaining three per-queue */
536 mqstat
->mq_msgsize
= attr
->mq_msgsize
;
537 mqstat
->mq_curmsgs
= attr
->mq_curmsgs
;
539 ipc_mutex_unlock (mqinfo
->mqi_lock
);
548 mq_setattr (mqd_t mqd
, const struct mq_attr
*mqstat
, struct mq_attr
*omqstat
)
551 struct mq_hdr
*mqhdr
;
552 struct mq_fattr
*attr
;
553 struct mq_info
*mqinfo
;
557 cygheap_fdget
fd ((int) mqd
, true);
558 mqinfo
= get_mqinfo (fd
);
559 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
564 mqhdr
= mqinfo
->mqi_hdr
;
565 attr
= &mqhdr
->mqh_attr
;
566 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, false)) != 0)
574 omqstat
->mq_flags
= mqinfo
->mqi_flags
; /* previous attributes */
575 omqstat
->mq_maxmsg
= attr
->mq_maxmsg
;
576 omqstat
->mq_msgsize
= attr
->mq_msgsize
;
577 omqstat
->mq_curmsgs
= attr
->mq_curmsgs
; /* and current status */
580 if (mqstat
->mq_flags
& O_NONBLOCK
)
581 mqinfo
->mqi_flags
|= O_NONBLOCK
;
583 mqinfo
->mqi_flags
&= ~O_NONBLOCK
;
585 ipc_mutex_unlock (mqinfo
->mqi_lock
);
594 mq_notify (mqd_t mqd
, const struct sigevent
*notification
)
598 struct mq_hdr
*mqhdr
;
599 struct mq_info
*mqinfo
;
603 cygheap_fdget
fd ((int) mqd
, true);
604 mqinfo
= get_mqinfo (fd
);
605 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
610 mqhdr
= mqinfo
->mqi_hdr
;
611 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, false)) != 0)
620 if (mqhdr
->mqh_pid
== pid
)
621 mqhdr
->mqh_pid
= 0; /* unregister calling process */
625 if (mqhdr
->mqh_pid
!= 0)
627 if (kill (mqhdr
->mqh_pid
, 0) != -1 || errno
!= ESRCH
)
630 ipc_mutex_unlock (mqinfo
->mqi_lock
);
634 mqhdr
->mqh_pid
= pid
;
635 mqhdr
->mqh_event
= *notification
;
637 ipc_mutex_unlock (mqinfo
->mqi_lock
);
646 _mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
647 const struct timespec
*abstime
)
650 long index
, freeindex
;
652 struct sigevent
*sigev
;
653 struct mq_hdr
*mqhdr
;
654 struct mq_fattr
*attr
;
655 struct msg_hdr
*msghdr
, *nmsghdr
, *pmsghdr
;
656 struct mq_info
*mqinfo
= NULL
;
657 bool ipc_mutex_locked
= false;
660 pthread_testcancel ();
664 cygheap_fdget
fd ((int) mqd
);
665 mqinfo
= get_mqinfo (fd
);
666 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
671 if (prio
>= MQ_PRIO_MAX
)
677 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
678 mptr
= (int8_t *) mqhdr
; /* byte pointer */
679 attr
= &mqhdr
->mqh_attr
;
680 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, true)) != 0)
685 ipc_mutex_locked
= true;
686 if (len
> (size_t) attr
->mq_msgsize
)
688 set_errno (EMSGSIZE
);
691 if (attr
->mq_curmsgs
== 0)
693 if (mqhdr
->mqh_pid
!= 0 && mqhdr
->mqh_nwait
== 0)
695 sigev
= &mqhdr
->mqh_event
;
696 if (sigev
->sigev_notify
== SIGEV_SIGNAL
)
697 sigqueue (mqhdr
->mqh_pid
, sigev
->sigev_signo
,
699 mqhdr
->mqh_pid
= 0; /* unregister */
702 else if (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
705 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
710 /* Wait for room for one message on the queue */
711 while (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
713 int ret
= ipc_cond_timedwait (mqinfo
->mqi_waitsend
,
714 mqinfo
->mqi_lock
, abstime
);
723 /* nmsghdr will point to new message */
724 if ((freeindex
= mqhdr
->mqh_free
) == 0)
725 api_fatal ("mq_send: curmsgs = %ld; free = 0", attr
->mq_curmsgs
);
727 nmsghdr
= (struct msg_hdr
*) &mptr
[freeindex
];
728 nmsghdr
->msg_prio
= prio
;
729 nmsghdr
->msg_len
= len
;
730 memcpy (nmsghdr
+ 1, ptr
, len
); /* copy message from caller */
731 mqhdr
->mqh_free
= nmsghdr
->msg_next
; /* new freelist head */
733 /* Find right place for message in linked list */
734 index
= mqhdr
->mqh_head
;
735 pmsghdr
= (struct msg_hdr
*) &(mqhdr
->mqh_head
);
738 msghdr
= (struct msg_hdr
*) &mptr
[index
];
739 if (prio
> msghdr
->msg_prio
)
741 nmsghdr
->msg_next
= index
;
742 pmsghdr
->msg_next
= freeindex
;
745 index
= msghdr
->msg_next
;
750 /* Queue was empty or new goes at end of list */
751 pmsghdr
->msg_next
= freeindex
;
752 nmsghdr
->msg_next
= 0;
754 /* Wake up anyone blocked in mq_receive waiting for a message */
755 if (attr
->mq_curmsgs
== 0)
756 ipc_cond_signal (mqinfo
->mqi_waitrecv
);
763 if (ipc_mutex_locked
)
764 ipc_mutex_unlock (mqinfo
->mqi_lock
);
769 mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
)
771 return _mq_send (mqd
, ptr
, len
, prio
, NULL
);
775 mq_timedsend (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
776 const struct timespec
*abstime
)
778 return _mq_send (mqd
, ptr
, len
, prio
, abstime
);
782 _mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
783 const struct timespec
*abstime
)
789 struct mq_hdr
*mqhdr
;
790 struct mq_fattr
*attr
;
791 struct msg_hdr
*msghdr
;
792 struct mq_info
*mqinfo
;
793 bool ipc_mutex_locked
= false;
795 pthread_testcancel ();
799 cygheap_fdget
fd ((int) mqd
);
800 mqinfo
= get_mqinfo (fd
);
801 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
806 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
807 mptr
= (int8_t *) mqhdr
; /* byte pointer */
808 attr
= &mqhdr
->mqh_attr
;
809 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, true)) != 0)
814 ipc_mutex_locked
= true;
815 if (maxlen
< (size_t) attr
->mq_msgsize
)
817 set_errno (EMSGSIZE
);
820 if (attr
->mq_curmsgs
== 0) /* queue is empty */
822 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
827 /* Wait for a message to be placed onto queue */
829 while (attr
->mq_curmsgs
== 0)
831 int ret
= ipc_cond_timedwait (mqinfo
->mqi_waitrecv
,
832 mqinfo
->mqi_lock
, abstime
);
842 if ((index
= mqhdr
->mqh_head
) == 0)
843 api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr
->mq_curmsgs
);
845 msghdr
= (struct msg_hdr
*) &mptr
[index
];
846 mqhdr
->mqh_head
= msghdr
->msg_next
; /* new head of list */
847 len
= msghdr
->msg_len
;
848 memcpy(ptr
, msghdr
+ 1, len
); /* copy the message itself */
850 *priop
= msghdr
->msg_prio
;
852 /* Just-read message goes to front of free list */
853 msghdr
->msg_next
= mqhdr
->mqh_free
;
854 mqhdr
->mqh_free
= index
;
856 /* Wake up anyone blocked in mq_send waiting for room */
857 if (attr
->mq_curmsgs
== attr
->mq_maxmsg
)
858 ipc_cond_signal (mqinfo
->mqi_waitsend
);
863 if (ipc_mutex_locked
)
864 ipc_mutex_unlock (mqinfo
->mqi_lock
);
869 mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
)
871 return _mq_receive (mqd
, ptr
, maxlen
, priop
, NULL
);
875 mq_timedreceive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
876 const struct timespec
*abstime
)
878 return _mq_receive (mqd
, ptr
, maxlen
, priop
, abstime
);
886 cygheap_fdget
fd ((int) mqd
, true);
887 if (!fd
->is_mqueue ())
893 if (mq_notify (mqd
, NULL
)) /* unregister calling process */
907 mq_unlink (const char *name
)
909 size_t len
= strlen (name
);
910 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
912 if (!check_path (mqname
, mqueue
, name
, len
))
914 if (unlink (mqname
) == -1)
919 /* POSIX named semaphore implementation. Loosely based on Richard W. STEPHENS
920 implementation as far as sem_open is concerned, but under the hood using
921 the already existing semaphore class in thread.cc. Using a file backed
922 solution allows to implement kernel persistent named semaphores. */
927 unsigned long long hash
;
932 sem_open (const char *name
, int oflag
, ...)
934 int i
, fd
= -1, created
= 0;
937 unsigned int value
= 0;
938 struct stat statbuff
;
939 sem_t
*sem
= SEM_FAILED
;
941 bool wasopen
= false;
944 size_t len
= strlen (name
);
945 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
947 if (!check_path (semname
, semaphore
, name
, len
))
952 oflag
&= (O_CREAT
| O_EXCL
);
957 va_start (ap
, oflag
); /* init ap to final named argument */
958 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
959 value
= va_arg (ap
, unsigned int);
962 /* Open and specify O_EXCL and user-execute */
963 fd
= open (semname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
,
967 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
968 goto exists
; /* already exists, OK */
972 /* First one to create the file initializes it. */
973 NtAllocateLocallyUniqueId (&sf
.luid
);
975 sf
.hash
= hash_path_name (0, semname
);
976 if (write (fd
, &sf
, sizeof sf
) != sizeof sf
)
978 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, value
,
980 if (sem
== SEM_FAILED
)
982 /* Initialization complete, turn off user-execute bit */
983 if (fchmod (fd
, mode
) == -1)
985 /* Don't close (fd); */
990 /* Open the file and fetch the semaphore name. */
991 if ((fd
= open (semname
, O_RDWR
| O_CLOEXEC
)) < 0)
993 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
997 /* Make certain initialization is complete */
998 for (i
= 0; i
< MAX_TRIES
; i
++)
1000 if (stat64 (semname
, &statbuff
) == -1)
1002 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1010 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
1016 set_errno (ETIMEDOUT
);
1019 if (file
.lock (fd
, sizeof sf
))
1021 if (read (fd
, &sf
, sizeof sf
) != sizeof sf
)
1023 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, sf
.value
,
1026 if (sem
== SEM_FAILED
)
1028 /* If wasopen is set, the semaphore was already opened and we already have
1029 an open file descriptor pointing to the file. This means, we have to
1030 close the file descriptor created in this call. It won't be stored
1036 __except (EFAULT
) {}
1038 /* Don't let following function calls change errno */
1045 if (sem
!= SEM_FAILED
)
1046 semaphore::close (sem
);
1053 _sem_close (sem_t
*sem
, bool do_close
)
1059 if (semaphore::getinternal (sem
, &fd
, &sf
.hash
, &sf
.luid
, &sf
.value
) == -1)
1061 if (!file
.lock (fd
, sizeof sf
)
1062 && lseek64 (fd
, 0LL, SEEK_SET
) != (off_t
) -1
1063 && write (fd
, &sf
, sizeof sf
) == sizeof sf
)
1064 ret
= do_close
? semaphore::close (sem
) : 0;
1066 /* Don't let following function calls change errno */
1075 sem_close (sem_t
*sem
)
1077 return _sem_close (sem
, true);
1081 sem_unlink (const char *name
)
1083 size_t len
= strlen (name
);
1084 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
1086 if (!check_path (semname
, semaphore
, name
, len
))
1088 if (unlink (semname
) == -1)
This page took 0.082535 seconds and 4 git commands to generate.