]>
sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/posix_ipc.cc
c286b248373e05235ad34dabdcb60c72ef1c1a93
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 __small_sprintf (buf
, "%scyg_pmtx/%s",
94 wincap
.has_terminal_services () ? "Global\\" : "", name
);
95 *pmtx
= CreateMutex (&sec_all
, FALSE
, buf
);
97 debug_printf ("failed: %E\n");
98 return *pmtx
? 0 : geterrno_from_win_error ();
102 ipc_mutex_lock (HANDLE mtx
)
104 HANDLE h
[2] = { mtx
, signal_arrived
};
106 switch (WaitForMultipleObjects (2, h
, FALSE
, INFINITE
))
109 case WAIT_ABANDONED_0
:
111 case WAIT_OBJECT_0
+ 1:
117 return geterrno_from_win_error ();
121 ipc_mutex_unlock (HANDLE mtx
)
123 return ReleaseMutex (mtx
) ? 0 : geterrno_from_win_error ();
127 ipc_mutex_close (HANDLE mtx
)
129 return CloseHandle (mtx
) ? 0 : geterrno_from_win_error ();
133 ipc_cond_init (HANDLE
*pevt
, const char *name
)
135 char buf
[CYG_MAX_PATH
];
136 strcpy (buf
, wincap
.has_terminal_services () ? "Global\\" : "");
137 __small_sprintf (buf
, "%scyg_pevt/%s",
138 wincap
.has_terminal_services () ? "Global\\" : "", name
);
139 *pevt
= CreateEvent (&sec_all
, TRUE
, FALSE
, buf
);
141 debug_printf ("failed: %E\n");
142 return *pevt
? 0 : geterrno_from_win_error ();
146 ipc_cond_timedwait (HANDLE evt
, HANDLE mtx
, const struct timespec
*abstime
)
150 HANDLE h
[2] = { mtx
, evt
};
154 else if (abstime
->tv_sec
< 0
155 || abstime
->tv_nsec
< 0
156 || abstime
->tv_nsec
> 999999999)
160 gettimeofday (&tv
, NULL
);
161 /* Check for immediate timeout. */
162 if (tv
.tv_sec
> abstime
->tv_sec
163 || (tv
.tv_sec
== abstime
->tv_sec
164 && tv
.tv_usec
> abstime
->tv_nsec
/ 1000))
166 timeout
= (abstime
->tv_sec
- tv
.tv_sec
) * 1000;
167 timeout
+= (abstime
->tv_nsec
/ 1000 - tv
.tv_usec
) / 1000;
169 if (ipc_mutex_unlock (mtx
))
171 switch (WaitForMultipleObjects (2, h
, TRUE
, timeout
))
174 case WAIT_ABANDONED_0
:
178 ipc_mutex_lock (mtx
);
183 return geterrno_from_win_error ();
187 ipc_cond_signal (HANDLE evt
)
189 return SetEvent (evt
) ? 0 : geterrno_from_win_error ();
193 ipc_cond_close (HANDLE evt
)
195 return CloseHandle (evt
) ? 0 : geterrno_from_win_error ();
198 /* POSIX shared memory object implementation. */
201 shm_open (const char *name
, int oflag
, mode_t mode
)
203 char shmname
[CYG_MAX_PATH
];
205 if (!check_path (shmname
, shmem
, name
))
208 /* Check for valid flags. */
209 if (((oflag
& O_ACCMODE
) != O_RDONLY
&& (oflag
& O_ACCMODE
) != O_RDWR
)
210 || (oflag
& ~(O_ACCMODE
| O_CREAT
| O_EXCL
| O_TRUNC
)))
212 debug_printf ("Invalid oflag 0%o", oflag
);
217 return open (shmname
, oflag
, mode
& 0777);
221 shm_unlink (const char *name
)
223 char shmname
[CYG_MAX_PATH
];
225 if (!check_path (shmname
, shmem
, name
))
228 return unlink (shmname
);
231 /* The POSIX message queue implementation is based on W. Richard STEVENS
232 implementation, just tweaked for Cygwin. The main change is
233 the usage of Windows mutexes and events instead of using the pthread
234 synchronization objects. The pathname is massaged so that the
235 files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
236 are implemented additionally. */
240 struct mq_attr mqh_attr
; /* the queue's attributes */
241 long mqh_head
; /* index of first message */
242 long mqh_free
; /* index of first free message */
243 long mqh_nwait
; /* #threads blocked in mq_receive() */
244 pid_t mqh_pid
; /* nonzero PID if mqh_event set */
245 char mqh_uname
[20]; /* unique name used to identify synchronization
246 objects connected to this queue */
247 struct sigevent mqh_event
; /* for mq_notify() */
252 long msg_next
; /* index of next on linked list */
253 ssize_t msg_len
; /* actual length */
254 unsigned int msg_prio
; /* priority */
259 struct mq_hdr
*mqi_hdr
; /* start of mmap'ed region */
260 unsigned long mqi_magic
; /* magic number if open */
261 int mqi_flags
; /* flags for this process */
262 HANDLE mqi_lock
; /* mutex lock */
263 HANDLE mqi_wait
; /* and condition variable */
266 #define MQI_MAGIC 0x98765432UL
268 #define MSGSIZE(i) roundup((i), sizeof(long))
270 #define MAX_TRIES 10 /* for waiting for initialization */
272 struct mq_attr defattr
= { 0, 10, 8192, 0 }; /* Linux defaults. */
274 extern "C" _off64_t
lseek64 (int, _off64_t
, int);
275 extern "C" void *mmap64 (void *, size_t, int, int, int, _off64_t
);
278 mq_open (const char *name
, int oflag
, ...)
280 int i
, fd
, nonblock
, created
;
282 _off64_t filesize
= 0;
286 struct __stat64 statbuff
;
287 struct mq_hdr
*mqhdr
;
288 struct msg_hdr
*msghdr
;
289 struct mq_attr
*attr
;
290 struct mq_info
*mqinfo
;
291 char mqname
[CYG_MAX_PATH
];
293 if (!check_path (mqname
, mqueue
, name
))
297 if (efault
.faulted (EFAULT
))
301 nonblock
= oflag
& O_NONBLOCK
;
302 oflag
&= ~O_NONBLOCK
;
303 mptr
= (int8_t *) MAP_FAILED
;
309 va_start (ap
, oflag
); /* init ap to final named argument */
310 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
311 attr
= va_arg (ap
, struct mq_attr
*);
314 /* Open and specify O_EXCL and user-execute */
315 fd
= open (mqname
, oflag
| O_EXCL
| O_RDWR
, mode
| S_IXUSR
);
318 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
319 goto exists
; /* already exists, OK */
323 /* First one to create the file initializes it */
326 else if (attr
->mq_maxmsg
<= 0 || attr
->mq_msgsize
<= 0)
331 /* Calculate and set the file size */
332 msgsize
= MSGSIZE (attr
->mq_msgsize
);
333 filesize
= sizeof (struct mq_hdr
)
334 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
335 if (lseek64 (fd
, filesize
- 1, SEEK_SET
) == -1)
337 if (write (fd
, "", 1) == -1)
340 /* Memory map the file */
341 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
343 if (mptr
== (int8_t *) MAP_FAILED
)
346 /* Allocate one mq_info{} for the queue */
347 if (!(mqinfo
= (struct mq_info
*) malloc (sizeof (struct mq_info
))))
349 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
350 mqinfo
->mqi_magic
= MQI_MAGIC
;
351 mqinfo
->mqi_flags
= nonblock
;
353 /* Initialize header at beginning of file */
354 /* Create free list with all messages on it */
355 mqhdr
->mqh_attr
.mq_flags
= 0;
356 mqhdr
->mqh_attr
.mq_maxmsg
= attr
->mq_maxmsg
;
357 mqhdr
->mqh_attr
.mq_msgsize
= attr
->mq_msgsize
;
358 mqhdr
->mqh_attr
.mq_curmsgs
= 0;
359 mqhdr
->mqh_nwait
= 0;
361 __small_sprintf (mqhdr
->mqh_uname
, "cyg%016X", hash_path_name (0,mqname
));
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
, mqhdr
->mqh_uname
);
379 i
= ipc_cond_init (&mqinfo
->mqi_wait
, mqhdr
->mqh_uname
);
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
= mqhdr
= (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
, mqhdr
->mqh_uname
);
439 i
= ipc_cond_init (&mqinfo
->mqi_wait
, mqhdr
->mqh_uname
);
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.070775 seconds and 5 git commands to generate.