From e98d3eb3eb9b6abd897e102031a14b7057641a65 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 14 Mar 2018 10:36:34 +0100 Subject: [PATCH] ctype: align size of category bit fields to small targets needs E.g. arm ABI requires -fshort-enums for bare-metal toolchains. Given there are only 29 category enums, the compiler chooses an 8 bit enum type, so a size of 11 bits for the bitfield leads to a compile time error: error: width of 'cat' exceeds its type enum category cat: 11; ^~~ Fix this by aligning the size of the category members to byte borders. Signed-off-by: Corinna Vinschen --- newlib/libc/ctype/categories.c | 4 +- winsup/cygwin/fhandler.h | 117 ++++++++----- winsup/cygwin/fhandler_socket_unix.cc | 229 +++++++++++++++----------- 3 files changed, 214 insertions(+), 136 deletions(-) diff --git a/newlib/libc/ctype/categories.c b/newlib/libc/ctype/categories.c index db285d7a5..c237324ec 100644 --- a/newlib/libc/ctype/categories.c +++ b/newlib/libc/ctype/categories.c @@ -2,8 +2,8 @@ #include "categories.h" struct _category { - enum category cat: 11; - unsigned int first: 21; + enum category cat: 8; + unsigned int first: 24; unsigned short delta; } __attribute__((packed)); diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 2e5020860..2d11030a9 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -579,8 +579,8 @@ class fhandler_socket: public fhandler_base void set_addr_family (int af) {addr_family = af;} int get_addr_family () {return addr_family;} - void set_socket_type (int st) { type = st;} - int get_socket_type () {return type;} + virtual void set_socket_type (int st) { type = st;} + virtual int get_socket_type () {return type;} /* select.cc */ virtual select_record *select_read (select_stuff *) = 0; @@ -825,6 +825,38 @@ class fhandler_socket_local: public fhandler_socket_wsock } }; +/* Sharable spinlock with low CPU profile and massively better + performance than OS mutex or event solutions. */ +class af_unix_spinlock_t +{ + LONG locked; /* 0 oder 1 */ + +public: + void lock () + { + LONG ret = InterlockedExchange (&locked, 1); + if (ret) + { + for (DWORD i = 0; ret; ++i) + { + Sleep ((i % 1024) >> 8); + ret = InterlockedExchange (&locked, 1); + } + } + } + void unlock () + { + InterlockedExchange (&locked, 0); + } +}; + +/* Internal representation of shutdown states */ +enum shut_state { + _SHUT_RECV = 1, + _SHUT_SEND = 2, + _SHUT_MASK = 3 +}; + class sun_name_t { public: @@ -835,19 +867,10 @@ class sun_name_t /* Allows 108 bytes sun_path plus trailing NUL */ char _nul[sizeof (struct sockaddr_un) + 1]; }; - sun_name_t (); - sun_name_t (const struct sockaddr *name, __socklen_t namelen); - - void *operator new (size_t) __attribute__ ((nothrow)) - { return cmalloc_abort (HEAP_FHANDLER, sizeof (sun_name_t)); } - void operator delete (void *p) {cfree (p);} -}; - -/* Internal representation of shutdown states */ -enum shut_state { - _SHUT_READ = 1, - _SHUT_WRITE = 2, - _SHUT_RW = 3 + sun_name_t () { set (NULL, 0); } + sun_name_t (const struct sockaddr *name, __socklen_t namelen) + { set ((const struct sockaddr_un *) name, namelen); } + void set (const struct sockaddr_un *name, __socklen_t namelen); }; /* For each AF_UNIX socket, we need to maintain socket-wide data, @@ -855,30 +878,29 @@ enum shut_state { in socket, socketpair or accept4 and reopened by dup, fork or exec. */ class af_unix_shmem_t { - SRWLOCK _bind_lock; - SRWLOCK _conn_lock; - SRWLOCK _io_lock; + /* Don't use SRWLOCKs here. They are not sharable. */ + af_unix_spinlock_t _bind_lock; + af_unix_spinlock_t _conn_lock; + af_unix_spinlock_t _state_lock; + af_unix_spinlock_t _io_lock; LONG _connection_state; /* conn_state */ LONG _binding_state; /* bind_state */ LONG _shutdown; /* shut_state */ LONG _so_error; /* SO_ERROR */ LONG _reuseaddr; /* dummy */ + int _type; /* socket type */ + sun_name_t sun_path; + sun_name_t peer_sun_path; public: - af_unix_shmem_t () - : _connection_state (unconnected), _binding_state (unbound), - _shutdown (0), _so_error (0) - { - InitializeSRWLock (&_bind_lock); - InitializeSRWLock (&_conn_lock); - InitializeSRWLock (&_io_lock); - } - void bind_lock () { AcquireSRWLockExclusive (&_bind_lock); } - void bind_unlock () { ReleaseSRWLockExclusive (&_bind_lock); } - void conn_lock () { AcquireSRWLockExclusive (&_conn_lock); } - void conn_unlock () { ReleaseSRWLockExclusive (&_conn_lock); } - void io_lock () { AcquireSRWLockExclusive (&_io_lock); } - void io_unlock () { ReleaseSRWLockExclusive (&_io_lock); } + void bind_lock () { _bind_lock.lock (); } + void bind_unlock () { _bind_lock.unlock (); } + void conn_lock () { _conn_lock.lock (); } + void conn_unlock () { _conn_lock.unlock (); } + void state_lock () { _state_lock.lock (); } + void state_unlock () { _state_lock.unlock (); } + void io_lock () { _io_lock.lock (); } + void io_unlock () { _io_lock.unlock (); } conn_state connect_state (conn_state val) { return (conn_state) InterlockedExchange (&_connection_state, val); } @@ -899,8 +921,20 @@ class af_unix_shmem_t int reuseaddr (int val) { return (int) InterlockedExchange (&_reuseaddr, val); } int reuseaddr () const { return _reuseaddr; } + + void set_socket_type (int val) { _type = val; } + int get_socket_type () const { return _type; } + + sun_name_t *get_sun_path () {return &sun_path;} + sun_name_t *get_peer_sun_path () {return &peer_sun_path;} + void set_sun_path (struct sockaddr_un *un, __socklen_t unlen) + { sun_path.set (un, unlen); } + void set_peer_sun_path (struct sockaddr_un *un, __socklen_t unlen) + { peer_sun_path.set (un, unlen); } }; +class af_unix_pkt_hdr_t; + class fhandler_socket_unix : public fhandler_socket { protected: @@ -913,14 +947,14 @@ class fhandler_socket_unix : public fhandler_socket HANDLE connect_wait_thr; HANDLE cwt_termination_evt; PVOID cwt_param; - sun_name_t *sun_path; - sun_name_t *peer_sun_path; struct ucred peer_cred; void bind_lock () { shmem->bind_lock (); } void bind_unlock () { shmem->bind_unlock (); } void conn_lock () { shmem->conn_lock (); } void conn_unlock () { shmem->conn_unlock (); } + void state_lock () { shmem->state_lock (); } + void state_unlock () { shmem->state_unlock (); } void io_lock () { shmem->io_lock (); } void io_unlock () { shmem->io_unlock (); } conn_state connect_state (conn_state val) @@ -935,6 +969,8 @@ class fhandler_socket_unix : public fhandler_socket int so_error () const { return shmem->so_error (); } int reuseaddr (int err) { return shmem->reuseaddr (err); } int reuseaddr () const { return shmem->reuseaddr (); } + void set_socket_type (int val) { shmem->set_socket_type (val); } + int get_socket_type () const { return shmem->get_socket_type (); } int create_shmem (); int reopen_shmem (); @@ -960,12 +996,14 @@ class fhandler_socket_unix : public fhandler_socket int connect_pipe (PUNICODE_STRING pipe_name); int listen_pipe (); int disconnect_pipe (HANDLE ph); - sun_name_t *get_sun_path () {return sun_path;} - sun_name_t *get_peer_sun_path () {return peer_sun_path;} - void set_sun_path (struct sockaddr_un *un, __socklen_t unlen); + sun_name_t *get_sun_path () {return shmem->get_sun_path ();} + sun_name_t *get_peer_sun_path () {return shmem->get_peer_sun_path ();} + void set_sun_path (struct sockaddr_un *un, __socklen_t unlen) + { shmem->set_sun_path (un, unlen); } void set_sun_path (sun_name_t *snt) { snt ? set_sun_path (&snt->un, snt->un_len) : set_sun_path (NULL, 0); } - void set_peer_sun_path (struct sockaddr_un *un, __socklen_t unlen); + void set_peer_sun_path (struct sockaddr_un *un, __socklen_t unlen) + { shmem->set_peer_sun_path (un, unlen); } void set_peer_sun_path (sun_name_t *snt) { snt ? set_peer_sun_path (&snt->un, snt->un_len) : set_peer_sun_path (NULL, 0); } @@ -973,6 +1011,9 @@ class fhandler_socket_unix : public fhandler_socket void fixup_after_fork (HANDLE parent); void fixup_after_exec (); void set_close_on_exec (bool val); + ssize_t recv_dgram (af_unix_pkt_hdr_t *packet, int flags); + ssize_t recv_stream (af_unix_pkt_hdr_t *packet, int flags); + ssize_t recv_eval (af_unix_pkt_hdr_t *packet, struct msghdr *msg, int flags); public: fhandler_socket_unix (); diff --git a/winsup/cygwin/fhandler_socket_unix.cc b/winsup/cygwin/fhandler_socket_unix.cc index 79fc4bc70..1bceaaf58 100644 --- a/winsup/cygwin/fhandler_socket_unix.cc +++ b/winsup/cygwin/fhandler_socket_unix.cc @@ -88,6 +88,8 @@ class af_unix_pkt_hdr_t uint16_t cmsg_len; /* size of ancillary data block */ uint16_t data_len; /* size of user data */ + af_unix_pkt_hdr_t (uint8_t s, uint8_t n, uint16_t c, uint16_t d) + { init (s, n, c, d); } void init (uint8_t s, uint8_t n, uint16_t c, uint16_t d) { shut_info = s; @@ -157,19 +159,14 @@ GUID __cygwin_socket_guid = { /* Default timeout value of connect: 20 secs, as on Linux. */ #define AF_UNIX_CONNECT_TIMEOUT (-20 * NS100PERSEC) -sun_name_t::sun_name_t () -{ - un_len = sizeof (sa_family_t); - un.sun_family = AF_UNIX; - _nul[sizeof (struct sockaddr_un)] = '\0'; -} - -sun_name_t::sun_name_t (const struct sockaddr *name, socklen_t namelen) +void +sun_name_t::set (const struct sockaddr_un *name, socklen_t namelen) { if (namelen < 0) namelen = 0; un_len = namelen < (__socklen_t) sizeof un ? namelen : sizeof un; - if (name) + un.sun_family = AF_UNIX; + if (name && un_len) memcpy (&un, name, un_len); _nul[sizeof (struct sockaddr_un)] = '\0'; } @@ -622,20 +619,18 @@ int fhandler_socket_unix::send_my_name () { sun_name_t *sun; - size_t name_len = 0; af_unix_pkt_hdr_t *packet; NTSTATUS status; IO_STATUS_BLOCK io; bind_lock (); sun = get_sun_path (); - name_len = sun ? sun->un_len : 0; - packet = (af_unix_pkt_hdr_t *) alloca (sizeof *packet + name_len); + packet = (af_unix_pkt_hdr_t *) alloca (sizeof *packet + sun->un_len); if (sun) - memcpy (AF_UNIX_PKT_NAME (packet), &sun->un, name_len); - bind_unlock (); + memcpy (AF_UNIX_PKT_NAME (packet), &sun->un, sun->un_len); - packet->init (0, name_len, 0, 0); + packet->init (0, sun->un_len, 0, 0); + bind_unlock (); /* The theory: Fire and forget. */ io_lock (); @@ -1008,27 +1003,6 @@ fhandler_socket_unix::disconnect_pipe (HANDLE ph) return 0; } -void -fhandler_socket_unix::set_sun_path (struct sockaddr_un *un, socklen_t unlen) -{ - if (peer_sun_path) - delete peer_sun_path; - if (!un) - sun_path = NULL; - sun_path = new sun_name_t ((const struct sockaddr *) un, unlen); -} - -void -fhandler_socket_unix::set_peer_sun_path (struct sockaddr_un *un, - socklen_t unlen) -{ - if (peer_sun_path) - delete peer_sun_path; - if (!un) - peer_sun_path = NULL; - peer_sun_path = new sun_name_t ((const struct sockaddr *) un, unlen); -} - void fhandler_socket_unix::set_cred () { @@ -1079,10 +1053,6 @@ fhandler_socket_unix::fhandler_socket_unix () fhandler_socket_unix::~fhandler_socket_unix () { - if (sun_path) - delete sun_path; - if (peer_sun_path) - delete peer_sun_path; } int @@ -1094,6 +1064,12 @@ fhandler_socket_unix::dup (fhandler_base *child, int flags) return -1; } fhandler_socket_unix *fhs = (fhandler_socket_unix *) child; + if (reopen_shmem () < 0) + { + __seterrno (); + fhs->close (); + return -1; + } if (backing_file_handle && backing_file_handle != INVALID_HANDLE_VALUE && !DuplicateHandle (GetCurrentProcess (), backing_file_handle, GetCurrentProcess (), &fhs->backing_file_handle, @@ -1111,12 +1087,6 @@ fhandler_socket_unix::dup (fhandler_base *child, int flags) fhs->close (); return -1; } - if (reopen_shmem () < 0) - { - __seterrno (); - fhs->close (); - return -1; - } fhs->set_sun_path (get_sun_path ()); fhs->set_peer_sun_path (get_peer_sun_path ()); fhs->connect_wait_thr = NULL; @@ -1248,7 +1218,7 @@ fhandler_socket_unix::socket (int af, int type, int protocol, int flags) return -1; rmem (262144); wmem (262144); - set_addr_family (af); + set_addr_family (AF_UNIX); set_socket_type (type); if (flags & SOCK_NONBLOCK) set_nonblocking (true); @@ -1279,13 +1249,17 @@ fhandler_socket_unix::socketpair (int af, int type, int protocol, int flags, return -1; } + if (create_shmem () < 0) + return -1; + if (fh->create_shmem () < 0) + goto fh_shmem_failed; /* socket() on both sockets */ rmem (262144); fh->rmem (262144); wmem (262144); fh->wmem (262144); - set_addr_family (af); - fh->set_addr_family (af); + set_addr_family (AF_UNIX); + fh->set_addr_family (AF_UNIX); set_socket_type (type); fh->set_socket_type (type); set_unique_id (); @@ -1294,31 +1268,15 @@ fhandler_socket_unix::socketpair (int af, int type, int protocol, int flags, gen_pipe_name (); pipe = create_pipe (true); if (!pipe) - return -1; + goto create_pipe_failed; set_io_handle (pipe); set_sun_path (&sun); fh->set_peer_sun_path (&sun); - if (create_shmem () < 0) - { - NtClose (pipe); - return -1; - } - binding_state (bound); connect_state (listener); - /* connect 2nd socket */ - if (type != SOCK_DGRAM - && fh->open_pipe (pc.get_nt_native_path (), false) < 0) - { - NtClose (shmem_handle); - NtClose (pipe); - return -1; - } - if (fh->create_shmem () < 0) - { - NtClose (fh->get_handle ()); - NtClose (shmem_handle); - NtClose (pipe); - } + /* connect 2nd socket, even for DGRAM. There's no difference as far + as socketpairs are concerned. */ + if (fh->open_pipe (pc.get_nt_native_path (), false) < 0) + goto fh_open_pipe_failed; fh->connect_state (connected); if (flags & SOCK_NONBLOCK) { @@ -1331,6 +1289,16 @@ fhandler_socket_unix::socketpair (int af, int type, int protocol, int flags, fh->set_close_on_exec (true); } return 0; + +fh_open_pipe_failed: + NtClose (pipe); +create_pipe_failed: + NtUnmapViewOfSection (GetCurrentProcess (), fh->shmem); + NtClose (fh->shmem_handle); +fh_shmem_failed: + NtUnmapViewOfSection (GetCurrentProcess (), shmem); + NtClose (shmem_handle); + return -1; } /* Bind creates the backing file, generates the pipe name and sets @@ -1471,7 +1439,7 @@ fhandler_socket_unix::accept4 (struct sockaddr *peer, int *len, int flags) if (sock->create_shmem () < 0) goto create_shmem_failed; - sock->set_addr_family (get_addr_family ()); + sock->set_addr_family (AF_UNIX); sock->set_socket_type (get_socket_type ()); if (flags & SOCK_NONBLOCK) sock->set_nonblocking (true); @@ -1609,36 +1577,60 @@ fhandler_socket_unix::connect (const struct sockaddr *name, int namelen) int fhandler_socket_unix::getsockname (struct sockaddr *name, int *namelen) { - sun_name_t sun; + sun_name_t *sun = get_sun_path (); - if (get_sun_path ()) - memcpy (&sun, &get_sun_path ()->un, get_sun_path ()->un_len); - else - sun.un_len = 0; - memcpy (name, &sun, MIN (*namelen, sun.un_len)); - *namelen = sun.un_len; + memcpy (name, sun, MIN (*namelen, sun->un_len)); + *namelen = sun->un_len; return 0; } int fhandler_socket_unix::getpeername (struct sockaddr *name, int *namelen) { - sun_name_t sun; - - if (get_peer_sun_path ()) - memcpy (&sun, &get_peer_sun_path ()->un, get_peer_sun_path ()->un_len); - else - sun.un_len = 0; - memcpy (name, &sun, MIN (*namelen, sun.un_len)); - *namelen = sun.un_len; + sun_name_t *sun = get_peer_sun_path (); + memcpy (name, sun, MIN (*namelen, sun->un_len)); + *namelen = sun->un_len; return 0; } int fhandler_socket_unix::shutdown (int how) { - set_errno (EAFNOSUPPORT); - return -1; + NTSTATUS status = STATUS_SUCCESS; + IO_STATUS_BLOCK io; + + if (how < SHUT_RD || how > SHUT_RDWR) + { + set_errno (EINVAL); + return -1; + } + /* Convert SHUT_RD/SHUT_WR/SHUT_RDWR to _SHUT_RECV/_SHUT_SEND bits. */ + ++how; + state_lock (); + int old_shutdown_mask = saw_shutdown (); + int new_shutdown_mask = old_shutdown_mask | how; + if (new_shutdown_mask != old_shutdown_mask) + saw_shutdown (new_shutdown_mask); + state_unlock (); + if (new_shutdown_mask != old_shutdown_mask) + { + /* Send shutdown info to peer. Note that it's not necessarily fatal + if the info isn't sent here. The info will be reproduced by any + followup package sent to the peer. */ + af_unix_pkt_hdr_t packet (new_shutdown_mask, 0, 0, 0); + io_lock (); + set_pipe_non_blocking (true); + status = NtWriteFile (get_handle (), NULL, NULL, NULL, &io, &packet, + packet.pckt_len, NULL, NULL); + set_pipe_non_blocking (is_nonblocking ()); + io_unlock (); + } + if (!NT_SUCCESS (status)) + { + debug_printf ("Couldn't send shutdown info: NtWriteFile: %y", status); + return -1; + } + return 0; } int @@ -1658,16 +1650,17 @@ fhandler_socket_unix::close () PVOID param = InterlockedExchangePointer (&cwt_param, NULL); if (param) cfree (param); + HANDLE hdl = InterlockedExchangePointer (&get_handle (), NULL); + if (hdl) + NtClose (hdl); + if (backing_file_handle && backing_file_handle != INVALID_HANDLE_VALUE) + NtClose (backing_file_handle); HANDLE shm = InterlockedExchangePointer (&shmem_handle, NULL); if (shm) NtClose (shm); param = InterlockedExchangePointer ((PVOID *) &shmem, NULL); if (param) NtUnmapViewOfSection (GetCurrentProcess (), param); - if (get_handle ()) - NtClose (get_handle ()); - if (backing_file_handle && backing_file_handle != INVALID_HANDLE_VALUE) - NtClose (backing_file_handle); return 0; } @@ -1681,33 +1674,77 @@ fhandler_socket_unix::getpeereid (pid_t *pid, uid_t *euid, gid_t *egid) set_errno (EINVAL); return -1; } - conn_lock (); if (connect_state () != connected) set_errno (ENOTCONN); else { __try { + state_lock (); if (pid) *pid = peer_cred.pid; if (euid) *euid = peer_cred.uid; if (egid) *egid = peer_cred.gid; + state_unlock (); ret = 0; } __except (EFAULT) {} __endtry } - conn_unlock (); return ret; } +ssize_t +fhandler_socket_unix::recv_dgram (af_unix_pkt_hdr_t *packet, int flags) +{ + /* socketpair sockets already have a valid pipe handle! */ + return 0; +} + +ssize_t +fhandler_socket_unix::recv_stream (af_unix_pkt_hdr_t *packet, int flags) +{ + + io_lock (); + io_unlock (); + return 0; +} + +ssize_t +fhandler_socket_unix::recv_eval (af_unix_pkt_hdr_t *packet, struct msghdr *msg, + int flags) +{ + return 0; +} + ssize_t fhandler_socket_unix::recvmsg (struct msghdr *msg, int flags) { - set_errno (EAFNOSUPPORT); - return -1; + tmp_pathbuf tp; + af_unix_pkt_hdr_t *packet; + ssize_t ret; + + if ((flags & ~(MSG_CMSG_CLOEXEC | MSG_DONTWAIT | MSG_OOB | MSG_PEEK + | MSG_TRUNC | MSG_WAITALL)) != 0) + { + set_errno (EINVAL); + return -1; + } + if (flags & MSG_OOB) + { + set_errno (EOPNOTSUPP); + return -1; + } + if (saw_shutdown () & _SHUT_RECV) + return 0; /* EOF */ + packet = (af_unix_pkt_hdr_t *) tp.t_get (); + ret = (get_socket_type () == SOCK_DGRAM) ? recv_dgram (packet, flags) + : recv_stream (packet, flags); + if (ret > 0) + ret = recv_eval (packet, msg, flags); + return ret; } ssize_t