]>
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
11 /* TODO: POSIX semaphores are implemented in thread.cc right now. The
12 implementation in thread.cc disallows implementing kernel
13 persistent semaphores, so in the long run we should move the
14 implementation here, using file based shared memory instead. */
24 #include <sys/param.h>
36 const char *description
;
38 { "/dev/shm", "POSIX shared memory object" },
39 { "/dev/mqueue", "POSIX message queue" },
40 { "/dev/sem", "POSIX semaphore" }
51 check_path (char *res_name
, ipc_type_t type
, const char *name
)
53 /* Note that we require the existance of the apprpriate /dev subdirectories
54 for POSIX IPC object support, similar to Linux (which supports the
55 directories, but doesn't require to mount them). We don't create
56 these directory here, that's the task of the installer. But we check
57 for existance and give ample warning. */
58 path_conv
path (ipc_names
[type
].prefix
, PC_SYM_NOFOLLOW
);
59 if (path
.error
|| !path
.exists () || !path
.isdir ())
62 "Warning: '%s' does not exists or is not a directory.\n\n"
63 "%ss require the existance of this directory.\n"
64 "Create the directory '%s' and set the permissions to 01777.\n"
65 "For instance on the command line: mkdir -m 01777 %s\n",
66 ipc_names
[type
].prefix
, ipc_names
[type
].description
,
67 ipc_names
[type
].prefix
, ipc_names
[type
].prefix
);
71 /* Name must start with a single slash. */
72 if (!name
|| name
[0] != '/' || name
[1] == '/')
74 debug_printf ("Invalid %s name '%s'", ipc_names
[type
].description
, name
);
78 if (strlen (name
) > CYG_MAX_PATH
- sizeof (ipc_names
[type
].prefix
))
80 debug_printf ("%s name '%s' too long", ipc_names
[type
].description
, name
);
81 set_errno (ENAMETOOLONG
);
84 strcpy (res_name
, ipc_names
[type
].prefix
);
85 strcat (res_name
, name
);
90 ipc_mutex_init (HANDLE
*pmtx
, const char *name
)
92 char buf
[CYG_MAX_PATH
];
93 strcpy (buf
, "cyg_pmtx");
95 for (char *c
= buf
; c
= strchr (c
+ 1, '\\'); ++c
)
97 *pmtx
= CreateMutex (&sec_all
, FALSE
, buf
);
99 debug_printf ("failed: %E\n");
100 return *pmtx
? 0 : geterrno_from_win_error ();
104 ipc_mutex_lock (HANDLE mtx
)
106 HANDLE h
[2] = { mtx
, signal_arrived
};
108 switch (WaitForMultipleObjects (2, h
, FALSE
, INFINITE
))
111 case WAIT_ABANDONED_0
:
113 case WAIT_OBJECT_0
+ 1:
119 return geterrno_from_win_error ();
123 ipc_mutex_unlock (HANDLE mtx
)
125 return ReleaseMutex (mtx
) ? 0 : geterrno_from_win_error ();
129 ipc_mutex_close (HANDLE mtx
)
131 return CloseHandle (mtx
) ? 0 : geterrno_from_win_error ();
135 ipc_cond_init (HANDLE
*pevt
, const char *name
)
137 char buf
[CYG_MAX_PATH
];
138 strcpy (buf
, "cyg_pevt");
140 for (char *c
= buf
; c
= strchr (c
+ 1, '\\'); ++c
)
142 *pevt
= CreateEvent (&sec_all
, TRUE
, FALSE
, buf
);
144 debug_printf ("failed: %E\n");
145 return *pevt
? 0 : geterrno_from_win_error ();
149 ipc_cond_timedwait (HANDLE evt
, HANDLE mtx
, const struct timespec
*abstime
)
153 HANDLE h
[2] = { mtx
, evt
};
157 else if (abstime
->tv_sec
< 0
158 || abstime
->tv_nsec
< 0
159 || abstime
->tv_nsec
> 999999999)
163 gettimeofday (&tv
, NULL
);
164 /* Check for immediate timeout. */
165 if (tv
.tv_sec
> abstime
->tv_sec
166 || (tv
.tv_sec
== abstime
->tv_sec
167 && tv
.tv_usec
> abstime
->tv_nsec
/ 1000))
169 timeout
= (abstime
->tv_sec
- tv
.tv_sec
) * 1000;
170 timeout
+= (abstime
->tv_nsec
/ 1000 - tv
.tv_usec
) / 1000;
172 if (ipc_mutex_unlock (mtx
))
174 switch (WaitForMultipleObjects (2, h
, TRUE
, timeout
))
177 case WAIT_ABANDONED_0
:
181 ipc_mutex_lock (mtx
);
186 return geterrno_from_win_error ();
190 ipc_cond_signal (HANDLE evt
)
192 return SetEvent (evt
) ? 0 : geterrno_from_win_error ();
196 ipc_cond_close (HANDLE evt
)
198 return CloseHandle (evt
) ? 0 : geterrno_from_win_error ();
201 /* POSIX shared memory object implementation. */
204 shm_open (const char *name
, int oflag
, mode_t mode
)
206 char shmname
[CYG_MAX_PATH
];
208 if (!check_path (shmname
, shmem
, name
))
211 /* Check for valid flags. */
212 if (((oflag
& O_ACCMODE
) != O_RDONLY
&& (oflag
& O_ACCMODE
) != O_RDWR
)
213 || (oflag
& ~(O_ACCMODE
| O_CREAT
| O_EXCL
| O_TRUNC
)))
215 debug_printf ("Invalid oflag 0%o", oflag
);
220 return open (shmname
, oflag
, mode
& 0777);
224 shm_unlink (const char *name
)
226 char shmname
[CYG_MAX_PATH
];
228 if (!check_path (shmname
, shmem
, name
))
231 return unlink (shmname
);
234 /* The POSIX message queue implementation is based on W. Richard STEVENS
235 implementation, just tweaked for Cygwin. The main change is
236 the usage of Windows mutexes and events instead of using the pthread
237 synchronization objects. The pathname is massaged so that the
238 files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
239 are implemented additionally. */
243 struct mq_attr mqh_attr
; /* the queue's attributes */
244 long mqh_head
; /* index of first message */
245 long mqh_free
; /* index of first free message */
246 long mqh_nwait
; /* #threads blocked in mq_receive() */
247 pid_t mqh_pid
; /* nonzero PID if mqh_event set */
248 struct sigevent mqh_event
; /* for mq_notify() */
253 long msg_next
; /* index of next on linked list */
254 ssize_t msg_len
; /* actual length */
255 unsigned int msg_prio
; /* priority */
260 struct mq_hdr
*mqi_hdr
; /* start of mmap'ed region */
261 unsigned long mqi_magic
; /* magic number if open */
262 int mqi_flags
; /* flags for this process */
263 HANDLE mqi_lock
; /* mutex lock */
264 HANDLE mqi_wait
; /* and condition variable */
267 #define MQI_MAGIC 0x98765432UL
269 #define MSGSIZE(i) roundup((i), sizeof(long))
271 #define MAX_TRIES 10 /* for waiting for initialization */
273 struct mq_attr defattr
= { 0, 10, 8192, 0 }; /* Linux defaults. */
275 extern "C" _off64_t
lseek64 (int, _off64_t
, int);
276 extern "C" void *mmap64 (void *, size_t, int, int, int, _off64_t
);
279 mq_open (const char *name
, int oflag
, ...)
281 int i
, fd
, nonblock
, created
;
287 struct __stat64 statbuff
;
288 struct mq_hdr
*mqhdr
;
289 struct msg_hdr
*msghdr
;
290 struct mq_attr
*attr
;
291 struct mq_info
*mqinfo
;
292 char mqname
[CYG_MAX_PATH
];
294 if (!check_path (mqname
, mqueue
, name
))
298 if (efault
.faulted (EFAULT
))
302 nonblock
= oflag
& O_NONBLOCK
;
303 oflag
&= ~O_NONBLOCK
;
304 mptr
= (int8_t *) MAP_FAILED
;
310 va_start (ap
, oflag
); /* init ap to final named argument */
311 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
312 attr
= va_arg (ap
, struct mq_attr
*);
315 /* Open and specify O_EXCL and user-execute */
316 fd
= open (mqname
, oflag
| O_EXCL
| O_RDWR
, mode
| S_IXUSR
);
319 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
320 goto exists
; /* already exists, OK */
324 /* First one to create the file initializes it */
327 else if (attr
->mq_maxmsg
<= 0 || attr
->mq_msgsize
<= 0)
332 /* Calculate and set the file size */
333 msgsize
= MSGSIZE (attr
->mq_msgsize
);
334 filesize
= sizeof (struct mq_hdr
)
335 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
336 if (lseek64 (fd
, filesize
- 1, SEEK_SET
) == -1)
338 if (write (fd
, "", 1) == -1)
341 /* Memory map the file */
342 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
344 if (mptr
== (int8_t *) MAP_FAILED
)
347 /* Allocate one mq_info{} for the queue */
348 if (!(mqinfo
= (struct mq_info
*) malloc (sizeof (struct mq_info
))))
350 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
351 mqinfo
->mqi_magic
= MQI_MAGIC
;
352 mqinfo
->mqi_flags
= nonblock
;
354 /* Initialize header at beginning of file */
355 /* Create free list with all messages on it */
356 mqhdr
->mqh_attr
.mq_flags
= 0;
357 mqhdr
->mqh_attr
.mq_maxmsg
= attr
->mq_maxmsg
;
358 mqhdr
->mqh_attr
.mq_msgsize
= attr
->mq_msgsize
;
359 mqhdr
->mqh_attr
.mq_curmsgs
= 0;
360 mqhdr
->mqh_nwait
= 0;
363 index
= sizeof (struct mq_hdr
);
364 mqhdr
->mqh_free
= index
;
365 for (i
= 0; i
< attr
->mq_maxmsg
- 1; i
++)
367 msghdr
= (struct msg_hdr
*) &mptr
[index
];
368 index
+= sizeof (struct msg_hdr
) + msgsize
;
369 msghdr
->msg_next
= index
;
371 msghdr
= (struct msg_hdr
*) &mptr
[index
];
372 msghdr
->msg_next
= 0; /* end of free list */
374 /* Initialize mutex & condition variable */
375 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqname
);
379 i
= ipc_cond_init (&mqinfo
->mqi_wait
, mqname
);
383 /* Initialization complete, turn off user-execute bit */
384 if (fchmod (fd
, mode
) == -1)
387 return ((mqd_t
) mqinfo
);
391 /* Open the file then memory map */
392 if ((fd
= open (mqname
, O_RDWR
)) < 0)
394 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
398 /* Make certain initialization is complete */
399 for (i
= 0; i
< MAX_TRIES
; i
++)
401 if (stat64 (mqname
, &statbuff
) == -1)
403 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
410 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
416 set_errno (ETIMEDOUT
);
420 filesize
= statbuff
.st_size
;
421 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
423 if (mptr
== (int8_t *) MAP_FAILED
)
427 /* Allocate one mq_info{} for each open */
428 if (!(mqinfo
= (struct mq_info
*) malloc (sizeof (struct mq_info
))))
430 mqinfo
->mqi_hdr
= (struct mq_hdr
*) mptr
;
431 mqinfo
->mqi_magic
= MQI_MAGIC
;
432 mqinfo
->mqi_flags
= nonblock
;
434 /* Initialize mutex & condition variable */
435 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqname
);
439 i
= ipc_cond_init (&mqinfo
->mqi_wait
, mqname
);
443 return (mqd_t
) mqinfo
;
448 /* Don't let following function calls change errno */
453 if (mptr
!= (int8_t *) MAP_FAILED
)
454 munmap((void *) mptr
, (size_t) filesize
);
462 mq_getattr (mqd_t mqd
, struct mq_attr
*mqstat
)
465 struct mq_hdr
*mqhdr
;
466 struct mq_attr
*attr
;
467 struct mq_info
*mqinfo
;
470 if (efault
.faulted (EBADF
))
473 mqinfo
= (struct mq_info
*) mqd
;
474 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
479 mqhdr
= mqinfo
->mqi_hdr
;
480 attr
= &mqhdr
->mqh_attr
;
481 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
486 mqstat
->mq_flags
= mqinfo
->mqi_flags
; /* per-open */
487 mqstat
->mq_maxmsg
= attr
->mq_maxmsg
; /* remaining three per-queue */
488 mqstat
->mq_msgsize
= attr
->mq_msgsize
;
489 mqstat
->mq_curmsgs
= attr
->mq_curmsgs
;
491 ipc_mutex_unlock (mqinfo
->mqi_lock
);
496 mq_setattr (mqd_t mqd
, const struct mq_attr
*mqstat
, struct mq_attr
*omqstat
)
499 struct mq_hdr
*mqhdr
;
500 struct mq_attr
*attr
;
501 struct mq_info
*mqinfo
;
504 if (efault
.faulted (EBADF
))
507 mqinfo
= (struct mq_info
*) mqd
;
508 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
513 mqhdr
= mqinfo
->mqi_hdr
;
514 attr
= &mqhdr
->mqh_attr
;
515 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
523 omqstat
->mq_flags
= mqinfo
->mqi_flags
; /* previous attributes */
524 omqstat
->mq_maxmsg
= attr
->mq_maxmsg
;
525 omqstat
->mq_msgsize
= attr
->mq_msgsize
;
526 omqstat
->mq_curmsgs
= attr
->mq_curmsgs
; /* and current status */
529 if (mqstat
->mq_flags
& O_NONBLOCK
)
530 mqinfo
->mqi_flags
|= O_NONBLOCK
;
532 mqinfo
->mqi_flags
&= ~O_NONBLOCK
;
534 ipc_mutex_unlock (mqinfo
->mqi_lock
);
539 mq_notify (mqd_t mqd
, const struct sigevent
*notification
)
543 struct mq_hdr
*mqhdr
;
544 struct mq_info
*mqinfo
;
547 if (efault
.faulted (EBADF
))
550 mqinfo
= (struct mq_info
*) mqd
;
551 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
556 mqhdr
= mqinfo
->mqi_hdr
;
557 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
566 if (mqhdr
->mqh_pid
== pid
)
567 mqhdr
->mqh_pid
= 0; /* unregister calling process */
571 if (mqhdr
->mqh_pid
!= 0)
573 if (kill (mqhdr
->mqh_pid
, 0) != -1 || errno
!= ESRCH
)
576 ipc_mutex_unlock (mqinfo
->mqi_lock
);
580 mqhdr
->mqh_pid
= pid
;
581 mqhdr
->mqh_event
= *notification
;
583 ipc_mutex_unlock (mqinfo
->mqi_lock
);
588 _mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
589 const struct timespec
*abstime
)
592 long index
, freeindex
;
594 struct sigevent
*sigev
;
595 struct mq_hdr
*mqhdr
;
596 struct mq_attr
*attr
;
597 struct msg_hdr
*msghdr
, *nmsghdr
, *pmsghdr
;
598 struct mq_info
*mqinfo
;
601 if (efault
.faulted (EBADF
))
604 mqinfo
= (struct mq_info
*) mqd
;
605 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
610 if (prio
> MQ_PRIO_MAX
)
616 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
617 mptr
= (int8_t *) mqhdr
; /* byte pointer */
618 attr
= &mqhdr
->mqh_attr
;
619 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
625 if (len
> (size_t) attr
->mq_msgsize
)
627 set_errno (EMSGSIZE
);
630 if (attr
->mq_curmsgs
== 0)
632 if (mqhdr
->mqh_pid
!= 0 && mqhdr
->mqh_nwait
== 0)
634 sigev
= &mqhdr
->mqh_event
;
635 if (sigev
->sigev_notify
== SIGEV_SIGNAL
)
636 sigqueue (mqhdr
->mqh_pid
, sigev
->sigev_signo
, sigev
->sigev_value
);
637 mqhdr
->mqh_pid
= 0; /* unregister */
640 else if (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
643 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
648 /* Wait for room for one message on the queue */
649 while (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
650 ipc_cond_timedwait (mqinfo
->mqi_wait
, mqinfo
->mqi_lock
, abstime
);
653 /* nmsghdr will point to new message */
654 if ((freeindex
= mqhdr
->mqh_free
) == 0)
655 api_fatal ("mq_send: curmsgs = %ld; free = 0", attr
->mq_curmsgs
);
657 nmsghdr
= (struct msg_hdr
*) &mptr
[freeindex
];
658 nmsghdr
->msg_prio
= prio
;
659 nmsghdr
->msg_len
= len
;
660 memcpy (nmsghdr
+ 1, ptr
, len
); /* copy message from caller */
661 mqhdr
->mqh_free
= nmsghdr
->msg_next
; /* new freelist head */
663 /* Find right place for message in linked list */
664 index
= mqhdr
->mqh_head
;
665 pmsghdr
= (struct msg_hdr
*) &(mqhdr
->mqh_head
);
668 msghdr
= (struct msg_hdr
*) &mptr
[index
];
669 if (prio
> msghdr
->msg_prio
)
671 nmsghdr
->msg_next
= index
;
672 pmsghdr
->msg_next
= freeindex
;
675 index
= msghdr
->msg_next
;
680 /* Queue was empty or new goes at end of list */
681 pmsghdr
->msg_next
= freeindex
;
682 nmsghdr
->msg_next
= 0;
684 /* Wake up anyone blocked in mq_receive waiting for a message */
685 if (attr
->mq_curmsgs
== 0)
686 ipc_cond_signal (mqinfo
->mqi_wait
);
689 ipc_mutex_unlock (mqinfo
->mqi_lock
);
693 ipc_mutex_unlock (mqinfo
->mqi_lock
);
698 mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
)
700 return _mq_send (mqd
, ptr
, len
, prio
, NULL
);
704 mq_timedsend (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
705 const struct timespec
*abstime
)
707 return _mq_send (mqd
, ptr
, len
, prio
, abstime
);
711 _mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
712 const struct timespec
*abstime
)
718 struct mq_hdr
*mqhdr
;
719 struct mq_attr
*attr
;
720 struct msg_hdr
*msghdr
;
721 struct mq_info
*mqinfo
;
724 if (efault
.faulted (EBADF
))
727 mqinfo
= (struct mq_info
*) mqd
;
728 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
733 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
734 mptr
= (int8_t *) mqhdr
; /* byte pointer */
735 attr
= &mqhdr
->mqh_attr
;
736 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
742 if (maxlen
< (size_t) attr
->mq_msgsize
)
744 set_errno (EMSGSIZE
);
747 if (attr
->mq_curmsgs
== 0) /* queue is empty */
749 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
754 /* Wait for a message to be placed onto queue */
756 while (attr
->mq_curmsgs
== 0)
757 ipc_cond_timedwait (mqinfo
->mqi_wait
, mqinfo
->mqi_lock
, abstime
);
761 if ((index
= mqhdr
->mqh_head
) == 0)
762 api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr
->mq_curmsgs
);
764 msghdr
= (struct msg_hdr
*) &mptr
[index
];
765 mqhdr
->mqh_head
= msghdr
->msg_next
; /* new head of list */
766 len
= msghdr
->msg_len
;
767 memcpy(ptr
, msghdr
+ 1, len
); /* copy the message itself */
769 *priop
= msghdr
->msg_prio
;
771 /* Just-read message goes to front of free list */
772 msghdr
->msg_next
= mqhdr
->mqh_free
;
773 mqhdr
->mqh_free
= index
;
775 /* Wake up anyone blocked in mq_send waiting for room */
776 if (attr
->mq_curmsgs
== attr
->mq_maxmsg
)
777 ipc_cond_signal (mqinfo
->mqi_wait
);
780 ipc_mutex_unlock (mqinfo
->mqi_lock
);
784 ipc_mutex_unlock (mqinfo
->mqi_lock
);
789 mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
)
791 return _mq_receive (mqd
, ptr
, maxlen
, priop
, NULL
);
795 mq_timedreceive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
796 const struct timespec
*abstime
)
798 return _mq_receive (mqd
, ptr
, maxlen
, priop
, abstime
);
804 long msgsize
, filesize
;
805 struct mq_hdr
*mqhdr
;
806 struct mq_attr
*attr
;
807 struct mq_info
*mqinfo
;
810 if (efault
.faulted (EBADF
))
813 mqinfo
= (struct mq_info
*) mqd
;
814 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
819 mqhdr
= mqinfo
->mqi_hdr
;
820 attr
= &mqhdr
->mqh_attr
;
822 if (mq_notify (mqd
, NULL
)) /* unregister calling process */
825 msgsize
= MSGSIZE (attr
->mq_msgsize
);
826 filesize
= sizeof (struct mq_hdr
)
827 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
828 if (munmap (mqinfo
->mqi_hdr
, filesize
) == -1)
831 mqinfo
->mqi_magic
= 0; /* just in case */
832 ipc_cond_close (mqinfo
->mqi_wait
);
833 ipc_mutex_close (mqinfo
->mqi_lock
);
839 mq_unlink (const char *name
)
841 char mqname
[CYG_MAX_PATH
];
843 if (!check_path (mqname
, mqueue
, name
))
845 if (unlink (mqname
) == -1)
This page took 0.076605 seconds and 6 git commands to generate.