Cygwin: POSIX msg queues: implement open/mq_open entirely in fhandler
The mq_open call is just a framework now. This patch moves the entire functionality into fhandler_mqueue. To support standard OS calls (as on Linux), make fhandler_mqueue a derived class from fhandler_disk_file and keep the base handle the handle to the default stream, to allow implementing O_PATH functionlaity as well as reading from the file and NOT reading binary message queue data. Implement a standard fhandler_mqueue::open method, allowing, for instance, to touch a file under /dev/mqueue and if it doesn't exist, to create a message queue file. FIXME: This introduces a BAD HACK into path_conv::check, which needs reviewing. Keep the posix path intact in the fhandler, and change get_proc_fd_name accordingly to return only the basename plus leading slash for /proc/<PID>/fd. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
parent
a4e074672a
commit
b62450cf17
|
@ -3103,11 +3103,15 @@ class fhandler_timerfd : public fhandler_base
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class fhandler_mqueue: public fhandler_base
|
class fhandler_mqueue: public fhandler_disk_file
|
||||||
{
|
{
|
||||||
struct mq_info mqi;
|
struct mq_info mqi;
|
||||||
|
|
||||||
struct mq_info *_mqinfo (HANDLE, SIZE_T, mode_t, int, bool);
|
struct mq_info *_mqinfo (SIZE_T, mode_t, int, bool);
|
||||||
|
|
||||||
|
struct mq_info *mqinfo_create (struct mq_attr *, mode_t, int);
|
||||||
|
struct mq_info *mqinfo_open (int);
|
||||||
|
void mq_open_finish (bool success, bool created);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
fhandler_mqueue ();
|
fhandler_mqueue ();
|
||||||
|
@ -3118,14 +3122,9 @@ public:
|
||||||
|
|
||||||
char *get_proc_fd_name (char *);
|
char *get_proc_fd_name (char *);
|
||||||
|
|
||||||
struct mq_info *mqinfo_create (HANDLE _h, SIZE_T _s, mode_t _m, int _f)
|
int open (int, mode_t);
|
||||||
{
|
int mq_open (int, mode_t, struct mq_attr *);
|
||||||
return _mqinfo (_h, _s, _m, _f, false);
|
|
||||||
}
|
|
||||||
struct mq_info *mqinfo_open (HANDLE _h, SIZE_T _s, mode_t _m, int _f)
|
|
||||||
{
|
|
||||||
return _mqinfo (_h, _s, _m, _f, true);
|
|
||||||
}
|
|
||||||
struct mq_info *mqinfo () { return &mqi; }
|
struct mq_info *mqinfo () { return &mqi; }
|
||||||
|
|
||||||
void fixup_after_fork (HANDLE);
|
void fixup_after_fork (HANDLE);
|
||||||
|
|
|
@ -11,21 +11,124 @@ details. */
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "fhandler.h"
|
#include "fhandler.h"
|
||||||
#include "dtable.h"
|
#include "dtable.h"
|
||||||
|
#include <mqueue.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#define MSGSIZE(i) roundup((i), sizeof(long))
|
||||||
|
|
||||||
|
struct mq_attr defattr = { 0, 10, 8192, 0 }; /* Linux defaults. */
|
||||||
|
|
||||||
fhandler_mqueue::fhandler_mqueue () :
|
fhandler_mqueue::fhandler_mqueue () :
|
||||||
fhandler_base ()
|
fhandler_disk_file ()
|
||||||
{
|
{
|
||||||
nohandle (true);
|
|
||||||
close_on_exec (true);
|
close_on_exec (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fhandler_mqueue::open (int flags, mode_t mode)
|
||||||
|
{
|
||||||
|
/* FIXME: reopen by handle semantics missing yet */
|
||||||
|
flags &= ~(O_NOCTTY | O_PATH | O_BINARY | O_TEXT);
|
||||||
|
return mq_open (flags, mode, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fhandler_mqueue::mq_open (int oflags, mode_t mode, struct mq_attr *attr)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
PUNICODE_STRING mqstream;
|
||||||
|
OBJECT_ATTRIBUTES oa;
|
||||||
|
struct mq_info *mqinfo = NULL;
|
||||||
|
bool created = false;
|
||||||
|
|
||||||
|
if ((oflags & ~(O_ACCMODE | O_CLOEXEC | O_CREAT | O_EXCL | O_NONBLOCK))
|
||||||
|
|| (oflags & O_ACCMODE) == O_ACCMODE)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* attach a stream suffix to the NT filename, thus creating a stream. */
|
||||||
|
mqstream = pc.get_nt_native_path (&ro_u_mq_suffix);
|
||||||
|
pc.get_object_attr (oa, sec_none_nih);
|
||||||
|
|
||||||
|
again:
|
||||||
|
if (oflags & O_CREAT)
|
||||||
|
{
|
||||||
|
/* Create and disallow sharing */
|
||||||
|
status = NtCreateFile (&get_handle (),
|
||||||
|
GENERIC_READ | GENERIC_WRITE | DELETE
|
||||||
|
| SYNCHRONIZE, &oa, &io, NULL,
|
||||||
|
FILE_ATTRIBUTE_NORMAL, FILE_SHARE_DELETE,
|
||||||
|
FILE_CREATE,
|
||||||
|
FILE_OPEN_FOR_BACKUP_INTENT
|
||||||
|
| FILE_SYNCHRONOUS_IO_NONALERT,
|
||||||
|
NULL, 0);
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
if (status == STATUS_OBJECT_NAME_COLLISION && (oflags & O_EXCL) == 0)
|
||||||
|
goto exists;
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (pc.has_acls ())
|
||||||
|
set_created_file_access (get_handle (), pc, mode);
|
||||||
|
created = true;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
exists:
|
||||||
|
/* Open the file, and loop while detecting a sharing violation. */
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
status = NtOpenFile (&get_handle (),
|
||||||
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
||||||
|
&oa, &io, FILE_SHARE_VALID_FLAGS,
|
||||||
|
FILE_OPEN_FOR_BACKUP_INTENT
|
||||||
|
| FILE_SYNCHRONOUS_IO_NONALERT);
|
||||||
|
if (NT_SUCCESS (status))
|
||||||
|
break;
|
||||||
|
if (status == STATUS_OBJECT_NAME_NOT_FOUND && (oflags & O_CREAT))
|
||||||
|
goto again;
|
||||||
|
if (status != STATUS_SHARING_VIOLATION)
|
||||||
|
{
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Sleep (100L);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
/* We need the filename without STREAM_SUFFIX later on */
|
||||||
|
mqstream->Length -= ro_u_mq_suffix.Length;
|
||||||
|
mqstream->Buffer[mqstream->Length / sizeof (WCHAR)] = L'\0';
|
||||||
|
|
||||||
|
if (created)
|
||||||
|
{
|
||||||
|
if (attr == NULL)
|
||||||
|
attr = &defattr;
|
||||||
|
/* Check minimum and maximum values. The max values are pretty much
|
||||||
|
arbitrary, taken from the linux mq_overview man page, up to Linux
|
||||||
|
3.4. These max values make sure that the internal mq_fattr
|
||||||
|
structure can use 32 bit types. */
|
||||||
|
if (attr->mq_maxmsg <= 0 || attr->mq_maxmsg > 32768
|
||||||
|
|| attr->mq_msgsize <= 0 || attr->mq_msgsize > 1048576)
|
||||||
|
set_errno (EINVAL);
|
||||||
|
else
|
||||||
|
mqinfo = mqinfo_create (attr, mode, oflags & O_NONBLOCK);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mqinfo = mqinfo_open (oflags & O_NONBLOCK);
|
||||||
|
mq_open_finish (mqinfo != NULL, created);
|
||||||
|
return mqinfo ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct mq_info *
|
struct mq_info *
|
||||||
fhandler_mqueue::_mqinfo (HANDLE fh, SIZE_T filesize, mode_t mode, int flags,
|
fhandler_mqueue::_mqinfo (SIZE_T filesize, mode_t mode, int flags,
|
||||||
bool just_open)
|
bool just_open)
|
||||||
{
|
{
|
||||||
WCHAR buf[NAME_MAX + sizeof ("mqueue/XXX")];
|
WCHAR buf[NAME_MAX + sizeof ("mqueue/XXX")];
|
||||||
UNICODE_STRING uname;
|
UNICODE_STRING uname;
|
||||||
OBJECT_ATTRIBUTES attr;
|
OBJECT_ATTRIBUTES oa;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
LARGE_INTEGER fsiz = { QuadPart: (LONGLONG) filesize };
|
LARGE_INTEGER fsiz = { QuadPart: (LONGLONG) filesize };
|
||||||
PVOID mptr = NULL;
|
PVOID mptr = NULL;
|
||||||
|
@ -38,33 +141,33 @@ fhandler_mqueue::_mqinfo (HANDLE fh, SIZE_T filesize, mode_t mode, int flags,
|
||||||
|
|
||||||
__small_swprintf (buf, L"mqueue/mtx%s", get_name ());
|
__small_swprintf (buf, L"mqueue/mtx%s", get_name ());
|
||||||
RtlInitUnicodeString (&uname, buf);
|
RtlInitUnicodeString (&uname, buf);
|
||||||
InitializeObjectAttributes (&attr, &uname, OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
InitializeObjectAttributes (&oa, &uname, OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
||||||
get_shared_parent_dir (),
|
get_shared_parent_dir (),
|
||||||
everyone_sd (CYG_MUTANT_ACCESS));
|
everyone_sd (CYG_MUTANT_ACCESS));
|
||||||
status = NtCreateMutant (&mqinfo ()->mqi_lock, CYG_MUTANT_ACCESS, &attr,
|
status = NtCreateMutant (&mqinfo ()->mqi_lock, CYG_MUTANT_ACCESS, &oa,
|
||||||
FALSE);
|
FALSE);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
wcsncpy (buf + 7, L"snd", 3);
|
wcsncpy (buf + 7, L"snd", 3);
|
||||||
/* same length, no RtlInitUnicodeString required */
|
/* same length, no RtlInitUnicodeString required */
|
||||||
InitializeObjectAttributes (&attr, &uname, OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
InitializeObjectAttributes (&oa, &uname, OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
||||||
get_shared_parent_dir (),
|
get_shared_parent_dir (),
|
||||||
everyone_sd (CYG_EVENT_ACCESS));
|
everyone_sd (CYG_EVENT_ACCESS));
|
||||||
status = NtCreateEvent (&mqinfo ()->mqi_waitsend, CYG_EVENT_ACCESS, &attr,
|
status = NtCreateEvent (&mqinfo ()->mqi_waitsend, CYG_EVENT_ACCESS, &oa,
|
||||||
NotificationEvent, FALSE);
|
NotificationEvent, FALSE);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
goto err;
|
goto err;
|
||||||
wcsncpy (buf + 7, L"rcv", 3);
|
wcsncpy (buf + 7, L"rcv", 3);
|
||||||
/* same length, same attributes, no more init required */
|
/* same length, same attributes, no more init required */
|
||||||
status = NtCreateEvent (&mqinfo ()->mqi_waitrecv, CYG_EVENT_ACCESS, &attr,
|
status = NtCreateEvent (&mqinfo ()->mqi_waitrecv, CYG_EVENT_ACCESS, &oa,
|
||||||
NotificationEvent, FALSE);
|
NotificationEvent, FALSE);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
InitializeObjectAttributes (&attr, NULL, 0, NULL, NULL);
|
InitializeObjectAttributes (&oa, NULL, 0, NULL, NULL);
|
||||||
status = NtCreateSection (&mqinfo ()->mqi_sect, SECTION_ALL_ACCESS, &attr,
|
status = NtCreateSection (&mqinfo ()->mqi_sect, SECTION_ALL_ACCESS, &oa,
|
||||||
&fsiz, PAGE_READWRITE, SEC_COMMIT, fh);
|
&fsiz, PAGE_READWRITE, SEC_COMMIT, get_handle ());
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@ -100,22 +203,152 @@ err:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct mq_info *
|
||||||
|
fhandler_mqueue::mqinfo_open (int flags)
|
||||||
|
{
|
||||||
|
FILE_STANDARD_INFORMATION fsi;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
NTSTATUS status;
|
||||||
|
mode_t mode;
|
||||||
|
|
||||||
|
fsi.EndOfFile.QuadPart = 0;
|
||||||
|
status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi,
|
||||||
|
FileStandardInformation);
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (get_file_attribute (get_handle (), pc, &mode, NULL, NULL))
|
||||||
|
mode = STD_RBITS | STD_WBITS;
|
||||||
|
|
||||||
|
return _mqinfo (fsi.EndOfFile.QuadPart, mode, flags, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mq_info *
|
||||||
|
fhandler_mqueue::mqinfo_create (struct mq_attr *attr, mode_t mode, int flags)
|
||||||
|
{
|
||||||
|
long msgsize;
|
||||||
|
off_t filesize = 0;
|
||||||
|
FILE_END_OF_FILE_INFORMATION feofi;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
NTSTATUS status;
|
||||||
|
struct mq_info *mqinfo = NULL;
|
||||||
|
|
||||||
|
msgsize = MSGSIZE (attr->mq_msgsize);
|
||||||
|
filesize = sizeof (struct mq_hdr)
|
||||||
|
+ (attr->mq_maxmsg * (sizeof (struct msg_hdr) + msgsize));
|
||||||
|
feofi.EndOfFile.QuadPart = filesize;
|
||||||
|
status = NtSetInformationFile (get_handle (), &io, &feofi, sizeof feofi,
|
||||||
|
FileEndOfFileInformation);
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mqinfo = _mqinfo (filesize, mode, flags, false);
|
||||||
|
|
||||||
|
if (mqinfo)
|
||||||
|
{
|
||||||
|
/* Initialize header at beginning of file */
|
||||||
|
/* Create free list with all messages on it */
|
||||||
|
int8_t *mptr;
|
||||||
|
struct mq_hdr *mqhdr;
|
||||||
|
struct msg_hdr *msghdr;
|
||||||
|
|
||||||
|
mptr = (int8_t *) mqinfo->mqi_hdr;
|
||||||
|
mqhdr = mqinfo->mqi_hdr;
|
||||||
|
mqhdr->mqh_attr.mq_flags = 0;
|
||||||
|
mqhdr->mqh_attr.mq_maxmsg = attr->mq_maxmsg;
|
||||||
|
mqhdr->mqh_attr.mq_msgsize = attr->mq_msgsize;
|
||||||
|
mqhdr->mqh_attr.mq_curmsgs = 0;
|
||||||
|
mqhdr->mqh_nwait = 0;
|
||||||
|
mqhdr->mqh_pid = 0;
|
||||||
|
mqhdr->mqh_head = 0;
|
||||||
|
mqhdr->mqh_magic = MQI_MAGIC;
|
||||||
|
long index = sizeof (struct mq_hdr);
|
||||||
|
mqhdr->mqh_free = index;
|
||||||
|
for (int i = 0; i < attr->mq_maxmsg - 1; i++)
|
||||||
|
{
|
||||||
|
msghdr = (struct msg_hdr *) &mptr[index];
|
||||||
|
index += sizeof (struct msg_hdr) + msgsize;
|
||||||
|
msghdr->msg_next = index;
|
||||||
|
}
|
||||||
|
msghdr = (struct msg_hdr *) &mptr[index];
|
||||||
|
msghdr->msg_next = 0; /* end of free list */
|
||||||
|
}
|
||||||
|
|
||||||
|
return mqinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fhandler_mqueue::mq_open_finish (bool success, bool created)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
HANDLE def_stream;
|
||||||
|
OBJECT_ATTRIBUTES oa;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
|
||||||
|
if (get_handle ())
|
||||||
|
{
|
||||||
|
/* If we have an open queue stream handle, close it and set it to NULL */
|
||||||
|
HANDLE queue_stream = get_handle ();
|
||||||
|
set_handle (NULL);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
/* In case of success, open the default stream for reading. This
|
||||||
|
can be used to implement various IO functions without exposing
|
||||||
|
the actual message queue. */
|
||||||
|
pc.get_object_attr (oa, sec_none_nih);
|
||||||
|
status = NtOpenFile (&def_stream, GENERIC_READ | SYNCHRONIZE,
|
||||||
|
&oa, &io, FILE_SHARE_VALID_FLAGS,
|
||||||
|
FILE_OPEN_FOR_BACKUP_INTENT
|
||||||
|
| FILE_SYNCHRONOUS_IO_NONALERT);
|
||||||
|
if (NT_SUCCESS (status))
|
||||||
|
set_handle (def_stream);
|
||||||
|
else /* Note that we don't treat this as an error! */
|
||||||
|
{
|
||||||
|
debug_printf ("Opening default stream failed: status %y", status);
|
||||||
|
nohandle (true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (created)
|
||||||
|
{
|
||||||
|
/* In case of error at creation time, delete the file */
|
||||||
|
FILE_DISPOSITION_INFORMATION disp = { TRUE };
|
||||||
|
|
||||||
|
NtSetInformationFile (queue_stream, &io, &disp, sizeof disp,
|
||||||
|
FileDispositionInformation);
|
||||||
|
/* We also have to set the delete disposition on the default stream,
|
||||||
|
otherwise only the queue stream will get deleted */
|
||||||
|
pc.get_object_attr (oa, sec_none_nih);
|
||||||
|
status = NtOpenFile (&def_stream, DELETE, &oa, &io,
|
||||||
|
FILE_SHARE_VALID_FLAGS,
|
||||||
|
FILE_OPEN_FOR_BACKUP_INTENT);
|
||||||
|
if (NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
NtSetInformationFile (def_stream, &io, &disp, sizeof disp,
|
||||||
|
FileDispositionInformation);
|
||||||
|
NtClose (def_stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NtClose (queue_stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
fhandler_mqueue::get_proc_fd_name (char *buf)
|
fhandler_mqueue::get_proc_fd_name (char *buf)
|
||||||
{
|
{
|
||||||
return strcpy (buf, get_name ());
|
return strcpy (buf, strrchr (get_name (), '/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
int __reg2
|
int __reg2
|
||||||
fhandler_mqueue::fstat (struct stat *buf)
|
fhandler_mqueue::fstat (struct stat *buf)
|
||||||
{
|
{
|
||||||
int ret = fhandler_base::fstat (buf);
|
int ret = fhandler_disk_file::fstat (buf);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
{
|
|
||||||
buf->st_mode = S_IFREG | mqinfo ()->mqi_mode;
|
|
||||||
buf->st_dev = FH_MQUEUE;
|
buf->st_dev = FH_MQUEUE;
|
||||||
buf->st_ino = hash_path_name (0, get_name ());
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -153,6 +153,7 @@ const int __collate_load_error = 0;
|
||||||
extern UNICODE_STRING _RDATA ro_u_natsyml = _ROU (L"SymbolicLink");
|
extern UNICODE_STRING _RDATA ro_u_natsyml = _ROU (L"SymbolicLink");
|
||||||
extern UNICODE_STRING _RDATA ro_u_natdev = _ROU (L"Device");
|
extern UNICODE_STRING _RDATA ro_u_natdev = _ROU (L"Device");
|
||||||
extern UNICODE_STRING _RDATA ro_u_npfs = _ROU (L"\\Device\\NamedPipe\\");
|
extern UNICODE_STRING _RDATA ro_u_npfs = _ROU (L"\\Device\\NamedPipe\\");
|
||||||
|
extern UNICODE_STRING _RDATA ro_u_mq_suffix = _ROU (L":mqueue");
|
||||||
#undef _ROU
|
#undef _ROU
|
||||||
|
|
||||||
/* This is an exported copy of environ which can be used by DLLs
|
/* This is an exported copy of environ which can be used by DLLs
|
||||||
|
|
|
@ -1225,6 +1225,18 @@ path_conv::check (const char *src, unsigned opt,
|
||||||
set_exec (1);
|
set_exec (1);
|
||||||
else if (issymlink () || issocket ())
|
else if (issymlink () || issocket ())
|
||||||
set_exec (0);
|
set_exec (0);
|
||||||
|
|
||||||
|
/* FIXME: bad hack alert!!! We need a better solution */
|
||||||
|
|
||||||
|
#define MQ_PATH "/dev/mqueue/"
|
||||||
|
#define MQ_LEN (sizeof (MQ_PATH) - 1)
|
||||||
|
|
||||||
|
if (!strncmp (src, MQ_PATH, MQ_LEN))
|
||||||
|
{
|
||||||
|
size_t len = strlen (src + MQ_LEN);
|
||||||
|
if (len > 0 && len <= NAME_MAX && !strpbrk (src + MQ_LEN, "/\\"))
|
||||||
|
dev.parse (FH_MQUEUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt & PC_NOFULL)
|
if (opt & PC_NOFULL)
|
||||||
|
|
|
@ -16,6 +16,7 @@ details. */
|
||||||
#include "cygheap.h"
|
#include "cygheap.h"
|
||||||
#include "sigproc.h"
|
#include "sigproc.h"
|
||||||
#include "ntdll.h"
|
#include "ntdll.h"
|
||||||
|
#include "tls_pbuf.h"
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
@ -24,8 +25,6 @@ details. */
|
||||||
#include <mqueue.h>
|
#include <mqueue.h>
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
|
|
||||||
extern "C" int ftruncate64 (int fd, off_t length);
|
|
||||||
|
|
||||||
/* The prefix_len is the length of the path prefix including trailing "/"
|
/* The prefix_len is the length of the path prefix including trailing "/"
|
||||||
(or "/sem." for semaphores) as well as the trailing NUL. */
|
(or "/sem." for semaphores) as well as the trailing NUL. */
|
||||||
static struct
|
static struct
|
||||||
|
@ -300,39 +299,13 @@ shm_unlink (const char *name)
|
||||||
files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
|
files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
|
||||||
are implemented additionally. */
|
are implemented additionally. */
|
||||||
|
|
||||||
#pragma pack (push, 4)
|
|
||||||
struct msg_hdr
|
|
||||||
{
|
|
||||||
int32_t msg_next; /* index of next on linked list */
|
|
||||||
int32_t msg_len; /* actual length */
|
|
||||||
unsigned int msg_prio; /* priority */
|
|
||||||
};
|
|
||||||
#pragma pack (pop)
|
|
||||||
|
|
||||||
#define MSGSIZE(i) roundup((i), sizeof(long))
|
|
||||||
|
|
||||||
#define MAX_TRIES 10 /* for waiting for initialization */
|
|
||||||
|
|
||||||
struct mq_attr defattr = { 0, 10, 8192, 0 }; /* Linux defaults. */
|
|
||||||
|
|
||||||
extern "C" off_t lseek64 (int, off_t, int);
|
|
||||||
extern "C" void *mmap64 (void *, size_t, int, int, int, off_t);
|
|
||||||
|
|
||||||
extern "C" mqd_t
|
extern "C" mqd_t
|
||||||
mq_open (const char *name, int oflag, ...)
|
mq_open (const char *name, int oflag, ...)
|
||||||
{
|
{
|
||||||
int i, fd = -1, nonblock, created = 0;
|
|
||||||
long msgsize, index;
|
|
||||||
off_t filesize = 0;
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
mode_t mode;
|
mode_t mode = 0;
|
||||||
fhandler_mqueue *fh = NULL;
|
fhandler_mqueue *fh = NULL;
|
||||||
struct stat statbuff;
|
struct mq_attr *attr = NULL;
|
||||||
int8_t *mptr = NULL;
|
|
||||||
struct mq_hdr *mqhdr;
|
|
||||||
struct msg_hdr *msghdr;
|
|
||||||
struct mq_attr *attr;
|
|
||||||
struct mq_info *mqinfo = NULL;
|
|
||||||
|
|
||||||
size_t len = strlen (name);
|
size_t len = strlen (name);
|
||||||
char mqname[ipc_names[mqueue].prefix_len + len];
|
char mqname[ipc_names[mqueue].prefix_len + len];
|
||||||
|
@ -342,155 +315,36 @@ mq_open (const char *name, int oflag, ...)
|
||||||
|
|
||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
oflag &= (O_CREAT | O_EXCL | O_NONBLOCK);
|
|
||||||
nonblock = oflag & O_NONBLOCK;
|
|
||||||
oflag &= ~O_NONBLOCK;
|
|
||||||
|
|
||||||
again:
|
|
||||||
if (oflag & O_CREAT)
|
if (oflag & O_CREAT)
|
||||||
{
|
{
|
||||||
va_start (ap, oflag); /* init ap to final named argument */
|
va_start (ap, oflag); /* init ap to final named argument */
|
||||||
mode = va_arg (ap, mode_t) & ~S_IXUSR;
|
mode = va_arg (ap, mode_t) & ~S_IXUSR;
|
||||||
attr = va_arg (ap, struct mq_attr *);
|
attr = va_arg (ap, struct mq_attr *);
|
||||||
va_end (ap);
|
va_end (ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create file descriptor for mqueue */
|
||||||
|
cygheap_fdnew fd;
|
||||||
|
|
||||||
/* Open and specify O_EXCL and user-execute */
|
|
||||||
fd = open (mqname, oflag | O_EXCL | O_RDWR | O_CLOEXEC,
|
|
||||||
mode | S_IXUSR);
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
|
||||||
if (errno == EEXIST && (oflag & O_EXCL) == 0)
|
|
||||||
goto exists; /* already exists, OK */
|
|
||||||
return (mqd_t) -1;
|
|
||||||
}
|
|
||||||
created = 1;
|
|
||||||
/* First one to create the file initializes it */
|
|
||||||
if (attr == NULL)
|
|
||||||
attr = &defattr;
|
|
||||||
/* Check minimum and maximum values. The max values are pretty much
|
|
||||||
arbitrary, taken from the linux mq_overview man page. However,
|
|
||||||
these max values make sure that the internal mq_fattr structure
|
|
||||||
can use 32 bit types. */
|
|
||||||
else if (attr->mq_maxmsg <= 0 || attr->mq_maxmsg > 32768
|
|
||||||
|| attr->mq_msgsize <= 0 || attr->mq_msgsize > 1048576)
|
|
||||||
{
|
|
||||||
set_errno (EINVAL);
|
|
||||||
__leave;
|
__leave;
|
||||||
}
|
fh = (fhandler_mqueue *) build_fh_name (mqname,
|
||||||
/* Calculate and set the file size */
|
PC_OPEN | PC_POSIX
|
||||||
msgsize = MSGSIZE (attr->mq_msgsize);
|
| PC_SYM_NOFOLLOW | PC_NULLEMPTY,
|
||||||
filesize = sizeof (struct mq_hdr)
|
NULL);
|
||||||
+ (attr->mq_maxmsg * (sizeof (struct msg_hdr) + msgsize));
|
|
||||||
if (ftruncate64 (fd, filesize) == -1)
|
|
||||||
__leave;
|
|
||||||
|
|
||||||
/* Create file descriptor for mqueue */
|
|
||||||
cygheap_fdnew fdm;
|
|
||||||
|
|
||||||
if (fdm < 0)
|
|
||||||
__leave;
|
|
||||||
fh = (fhandler_mqueue *) build_fh_dev (*mqueue_dev, name);
|
|
||||||
if (!fh)
|
if (!fh)
|
||||||
__leave;
|
__leave;
|
||||||
|
|
||||||
mqinfo = fh->mqinfo_create ((HANDLE) _get_osfhandle (fd), filesize,
|
if (fh->mq_open (oflag, mode, attr))
|
||||||
mode, nonblock);
|
|
||||||
if (!mqinfo)
|
|
||||||
__leave;
|
|
||||||
|
|
||||||
/* Initialize header at beginning of file */
|
|
||||||
/* Create free list with all messages on it */
|
|
||||||
mptr = (int8_t *) mqinfo->mqi_hdr;
|
|
||||||
mqhdr = mqinfo->mqi_hdr;
|
|
||||||
mqhdr->mqh_attr.mq_flags = 0;
|
|
||||||
mqhdr->mqh_attr.mq_maxmsg = attr->mq_maxmsg;
|
|
||||||
mqhdr->mqh_attr.mq_msgsize = attr->mq_msgsize;
|
|
||||||
mqhdr->mqh_attr.mq_curmsgs = 0;
|
|
||||||
mqhdr->mqh_nwait = 0;
|
|
||||||
mqhdr->mqh_pid = 0;
|
|
||||||
mqhdr->mqh_head = 0;
|
|
||||||
mqhdr->mqh_magic = MQI_MAGIC;
|
|
||||||
index = sizeof (struct mq_hdr);
|
|
||||||
mqhdr->mqh_free = index;
|
|
||||||
for (i = 0; i < attr->mq_maxmsg - 1; i++)
|
|
||||||
{
|
{
|
||||||
msghdr = (struct msg_hdr *) &mptr[index];
|
fd = fh;
|
||||||
index += sizeof (struct msg_hdr) + msgsize;
|
return (mqd_t) fd;
|
||||||
msghdr->msg_next = index;
|
|
||||||
}
|
}
|
||||||
msghdr = (struct msg_hdr *) &mptr[index];
|
|
||||||
msghdr->msg_next = 0; /* end of free list */
|
|
||||||
|
|
||||||
/* Initialization complete, turn off user-execute bit */
|
|
||||||
if (fchmod (fd, mode) == -1)
|
|
||||||
__leave;
|
|
||||||
close (fd);
|
|
||||||
fdm = fh;
|
|
||||||
return (mqd_t) fdm;
|
|
||||||
}
|
|
||||||
|
|
||||||
exists:
|
|
||||||
/* Open the file then memory map */
|
|
||||||
if ((fd = open (mqname, O_RDWR | O_CLOEXEC)) < 0)
|
|
||||||
{
|
|
||||||
if (errno == ENOENT && (oflag & O_CREAT))
|
|
||||||
goto again;
|
|
||||||
__leave;
|
|
||||||
}
|
|
||||||
/* Make certain initialization is complete */
|
|
||||||
for (i = 0; i < MAX_TRIES; i++)
|
|
||||||
{
|
|
||||||
if (stat64 (mqname, &statbuff) == -1)
|
|
||||||
{
|
|
||||||
if (errno == ENOENT && (oflag & O_CREAT))
|
|
||||||
{
|
|
||||||
close (fd);
|
|
||||||
fd = -1;
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
__leave;
|
|
||||||
}
|
|
||||||
if ((statbuff.st_mode & S_IXUSR) == 0)
|
|
||||||
break;
|
|
||||||
sleep (1);
|
|
||||||
}
|
|
||||||
if (i == MAX_TRIES)
|
|
||||||
{
|
|
||||||
set_errno (ETIMEDOUT);
|
|
||||||
__leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create file descriptor for mqueue */
|
|
||||||
cygheap_fdnew fdm;
|
|
||||||
|
|
||||||
if (fdm < 0)
|
|
||||||
__leave;
|
|
||||||
fh = (fhandler_mqueue *) build_fh_dev (*mqueue_dev, name);
|
|
||||||
if (!fh)
|
|
||||||
__leave;
|
|
||||||
|
|
||||||
mqinfo = fh->mqinfo_open ((HANDLE) _get_osfhandle (fd), statbuff.st_size,
|
|
||||||
statbuff.st_mode, nonblock);
|
|
||||||
if (!mqinfo)
|
|
||||||
__leave;
|
|
||||||
|
|
||||||
close (fd);
|
|
||||||
fdm = fh;
|
|
||||||
return (mqd_t) fdm;
|
|
||||||
}
|
}
|
||||||
__except (EFAULT) {}
|
__except (EFAULT) {}
|
||||||
__endtry
|
__endtry
|
||||||
/* Don't let following function calls change errno */
|
|
||||||
save_errno save;
|
|
||||||
if (created)
|
|
||||||
unlink (mqname);
|
|
||||||
if (fd >= 0)
|
|
||||||
close (fd);
|
|
||||||
if (fh)
|
if (fh)
|
||||||
{
|
|
||||||
fh->close ();
|
|
||||||
delete fh;
|
delete fh;
|
||||||
}
|
|
||||||
return (mqd_t) -1;
|
return (mqd_t) -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -921,6 +775,8 @@ mq_unlink (const char *name)
|
||||||
the already existing semaphore class in thread.cc. Using a file backed
|
the already existing semaphore class in thread.cc. Using a file backed
|
||||||
solution allows to implement kernel persistent named semaphores. */
|
solution allows to implement kernel persistent named semaphores. */
|
||||||
|
|
||||||
|
#define MAX_TRIES 10 /* for waiting for initialization */
|
||||||
|
|
||||||
struct sem_finfo
|
struct sem_finfo
|
||||||
{
|
{
|
||||||
unsigned int value;
|
unsigned int value;
|
||||||
|
@ -1049,6 +905,8 @@ sem_open (const char *name, int oflag, ...)
|
||||||
return SEM_FAILED;
|
return SEM_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" off_t lseek64 (int, off_t, int);
|
||||||
|
|
||||||
int
|
int
|
||||||
_sem_close (sem_t *sem, bool do_close)
|
_sem_close (sem_t *sem, bool do_close)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue