mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-02-08 18:19:08 +08:00
Cygwin: AF_UNIX: select: first cut
Untested. There are many FIXMEs that need attention. I haven't thought much about datagram sockets. Some of the code might only work for stream sockets.
This commit is contained in:
parent
84f97738a7
commit
7c04247105
@ -1420,7 +1420,7 @@ fhandler_dev_null::select_write (select_stuff *ss)
|
||||
if (!s->startup)
|
||||
{
|
||||
s->startup = no_startup;
|
||||
s->verify = no_verify;
|
||||
s->verify = verify_ok;
|
||||
}
|
||||
s->h = get_handle ();
|
||||
s->write_selected = true;
|
||||
@ -1864,48 +1864,288 @@ fhandler_socket_wsock::select_except (select_stuff *ss)
|
||||
|
||||
#ifdef __WITH_AF_UNIX
|
||||
|
||||
static int
|
||||
peek_socket_unix (select_record *me, bool)
|
||||
{
|
||||
/* Call grab_admin_pkt?
|
||||
If listening, check for connection.
|
||||
If connected, check for data in pipe. Use get_unread and peek_pipe.
|
||||
If writing, check whether there's room for a packet of size MAX_AF_PKT_LEN.
|
||||
Look at peek_socket for other things to check.
|
||||
*/
|
||||
int gotone = 0;
|
||||
fhandler_socket_unix *fh = (fhandler_socket_unix *) me->fh;
|
||||
if (me->read_selected)
|
||||
{
|
||||
if (me->read_ready)
|
||||
{
|
||||
select_printf ("%s, already ready for read", fh->get_name ());
|
||||
gotone = 1;
|
||||
goto out;
|
||||
}
|
||||
if (fh->get_unread ())
|
||||
{
|
||||
select_printf ("read: %s, ready for read", fh->get_name ());
|
||||
gotone += me->read_ready = true;
|
||||
goto out;
|
||||
}
|
||||
if (fh->connect_state () == connected)
|
||||
while (1)
|
||||
{
|
||||
PFILE_PIPE_PEEK_BUFFER pbuf
|
||||
= (PFILE_PIPE_PEEK_BUFFER) alloca (MAX_PATH);
|
||||
ULONG ret_len;
|
||||
/* FIXME: Is it OK to call peek_pipe with NULL evt? */
|
||||
NTSTATUS status = fh->peek_pipe (pbuf, MAX_PATH, NULL, ret_len);
|
||||
if (ret_len)
|
||||
{
|
||||
af_unix_pkt_hdr_t *packet = (af_unix_pkt_hdr_t *) pbuf->Data;
|
||||
if (packet->admin_pkt)
|
||||
{
|
||||
/* FIXME: Check for error? */
|
||||
fh->grab_admin_pkt (false);
|
||||
if (fh->saw_shutdown () & _SHUT_RECV)
|
||||
{
|
||||
select_printf ("read: %s, saw shutdown",
|
||||
fh->get_name ());
|
||||
gotone += me->read_ready = true;
|
||||
if (me->except_selected)
|
||||
gotone += me->except_ready = true;
|
||||
goto out;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (packet->data_len)
|
||||
{
|
||||
select_printf ("read: %s, ready for read: avail %d",
|
||||
fh->get_name (), packet->data_len);
|
||||
gotone += me->read_ready = true;
|
||||
goto out;
|
||||
}
|
||||
else if (fh->get_socket_type () == SOCK_DGRAM)
|
||||
{
|
||||
select_printf ("read: %s, ready for read: 0-length datagram packet",
|
||||
fh->get_name ());
|
||||
gotone += me->read_ready = true;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
select_printf ("read: %s, 0-length stream socket packet",
|
||||
fh->get_name ());
|
||||
gotone += me->read_ready = true;
|
||||
if (me->except_selected)
|
||||
gotone += me->except_ready = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if (!NT_SUCCESS (status))
|
||||
{
|
||||
select_printf ("peek_pipe status %y", status);
|
||||
gotone += me->read_ready = true;
|
||||
if (me->except_selected)
|
||||
gotone += me->except_ready = true;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if (fh->connect_state () == listener)
|
||||
{
|
||||
IO_STATUS_BLOCK io;
|
||||
FILE_PIPE_LOCAL_INFORMATION fpli;
|
||||
NTSTATUS status
|
||||
= NtQueryInformationFile (fh->get_handle (), &io,
|
||||
&fpli, sizeof (fpli),
|
||||
FilePipeLocalInformation);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
select_printf ("%s, NtQueryInformationFile failed, status %y",
|
||||
fh->get_name (), status);
|
||||
goto out;
|
||||
}
|
||||
if (fpli.NamedPipeState == FILE_PIPE_CONNECTED_STATE)
|
||||
{
|
||||
select_printf ("%s, pipe has connected", fh->get_name ());
|
||||
gotone += me->read_ready = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (me->write_selected)
|
||||
{
|
||||
if (me->write_ready)
|
||||
{
|
||||
select_printf ("%s, already ready for write", fh->get_name ());
|
||||
gotone += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: I'm not calling pipe_data_available because its
|
||||
for space available in the buffer doesn't make sense to
|
||||
me. Also, we probably don't want to consider the socket
|
||||
writable if there's only one byte available in the
|
||||
buffer. But maybe I've gone too far in insisting on
|
||||
MAX_AF_PKT_LEN bytes available. */
|
||||
IO_STATUS_BLOCK io;
|
||||
FILE_PIPE_LOCAL_INFORMATION fpli;
|
||||
NTSTATUS status
|
||||
= NtQueryInformationFile (fh->get_handle (), &io,
|
||||
&fpli, sizeof (fpli),
|
||||
FilePipeLocalInformation);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
select_printf ("%s, NtQueryInformationFile failed, status %y",
|
||||
fh->get_name (), status);
|
||||
/* See the comment in pipe_data_available. */
|
||||
gotone += me->write_ready = true;
|
||||
}
|
||||
else if (fpli.WriteQuotaAvailable >= MAX_AF_PKT_LEN)
|
||||
{
|
||||
select_printf ("%s, read for write", fh->get_name ());
|
||||
gotone += me->write_ready = true;
|
||||
}
|
||||
else
|
||||
select_printf ("%s, WriteQuotaAvailable %PRIu32", fh->get_name (),
|
||||
fpli.WriteQuotaAvailable);
|
||||
}
|
||||
}
|
||||
return gotone;
|
||||
}
|
||||
|
||||
static int start_thread_socket_unix (select_record *, select_stuff *);
|
||||
|
||||
static DWORD WINAPI
|
||||
thread_socket_unix (void *arg)
|
||||
{
|
||||
select_socket_unix_info *si = (select_socket_unix_info *) arg;
|
||||
DWORD sleep_time = 0;
|
||||
bool looping = true;
|
||||
|
||||
while (looping)
|
||||
{
|
||||
for (select_record *s = si->start; (s = s->next); )
|
||||
if (s->startup == start_thread_socket_unix)
|
||||
{
|
||||
if (peek_socket_unix (s, true))
|
||||
looping = false;
|
||||
if (si->stop_thread)
|
||||
{
|
||||
select_printf ("stopping");
|
||||
looping = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!looping)
|
||||
break;
|
||||
cygwait (si->bye, sleep_time >> 3);
|
||||
if (sleep_time < 80)
|
||||
++sleep_time;
|
||||
if (si->stop_thread)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
start_thread_socket_unix (select_record *me, select_stuff *stuff)
|
||||
{
|
||||
select_socket_unix_info *si = stuff->device_specific_socket_unix;
|
||||
if (si->start)
|
||||
me->h = *((select_socket_unix_info *) stuff->device_specific_socket_unix)->thread;
|
||||
else
|
||||
{
|
||||
si->start = &stuff->start;
|
||||
si->stop_thread = false;
|
||||
si->bye = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
|
||||
si->thread = new cygthread (thread_socket_unix, si, "sockunsel");
|
||||
me->h = *si->thread;
|
||||
if (!me->h)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
socket_unix_cleanup (select_record *, select_stuff *stuff)
|
||||
{
|
||||
select_socket_unix_info *si = (select_socket_unix_info *) stuff->device_specific_socket_unix;
|
||||
if (!si)
|
||||
return;
|
||||
if (si->thread)
|
||||
{
|
||||
si->stop_thread = true;
|
||||
SetEvent (si->bye);
|
||||
si->thread->detach ();
|
||||
CloseHandle (si->bye);
|
||||
}
|
||||
delete si;
|
||||
stuff->device_specific_socket_unix = NULL;
|
||||
}
|
||||
|
||||
/* FIXME: Initial select state depends on shutdown, as in wsock case. */
|
||||
|
||||
select_record *
|
||||
fhandler_socket_unix::select_read (select_stuff *ss)
|
||||
{
|
||||
if (!ss->device_specific_socket_unix
|
||||
&& (ss->device_specific_socket_unix = new select_socket_unix_info) == NULL)
|
||||
return NULL;
|
||||
select_record *s = ss->start.next;
|
||||
if (!s->startup)
|
||||
{
|
||||
s->startup = no_startup;
|
||||
s->verify = verify_ok;
|
||||
}
|
||||
s->h = get_handle_cyg ();
|
||||
s->startup = start_thread_socket_unix;
|
||||
s->peek = peek_socket_unix;
|
||||
s->verify = verify_ok;
|
||||
s->cleanup = socket_unix_cleanup;
|
||||
s->read_selected = true;
|
||||
s->read_ready = true;
|
||||
grab_admin_pkt ();
|
||||
/* FIXME: Is this right? The test for being connected isn't done
|
||||
for wsock sockets. */
|
||||
s->read_ready = (saw_shutdown () & _SHUT_RECV)
|
||||
|| connect_state () != connected;
|
||||
return s;
|
||||
}
|
||||
|
||||
select_record *
|
||||
fhandler_socket_unix::select_write (select_stuff *ss)
|
||||
{
|
||||
if (!ss->device_specific_socket_unix
|
||||
&& (ss->device_specific_socket_unix = new select_socket_unix_info) == NULL)
|
||||
return NULL;
|
||||
select_record *s = ss->start.next;
|
||||
if (!s->startup)
|
||||
{
|
||||
s->startup = no_startup;
|
||||
s->verify = verify_ok;
|
||||
}
|
||||
s->h = get_handle ();
|
||||
s->startup = start_thread_socket_unix;
|
||||
s->peek = peek_socket_unix;
|
||||
s->verify = verify_ok;
|
||||
s->cleanup = socket_unix_cleanup;
|
||||
s->write_selected = true;
|
||||
s->write_ready = true;
|
||||
s->write_ready = (saw_shutdown () & _SHUT_SEND)
|
||||
|| connect_state () == unconnected;
|
||||
if (connect_state () != unconnected)
|
||||
{
|
||||
/* FIXME: I copied this from the wsock case, but it doesn't seem
|
||||
right. Why are we setting except_ready here? */
|
||||
s->except_ready = saw_shutdown ();
|
||||
s->except_on_write = true;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
select_record *
|
||||
fhandler_socket_unix::select_except (select_stuff *ss)
|
||||
{
|
||||
if (!ss->device_specific_socket_unix
|
||||
&& (ss->device_specific_socket_unix = new select_socket_unix_info) == NULL)
|
||||
return NULL;
|
||||
select_record *s = ss->start.next;
|
||||
if (!s->startup)
|
||||
{
|
||||
s->startup = no_startup;
|
||||
s->verify = verify_ok;
|
||||
}
|
||||
s->h = NULL;
|
||||
s->startup = start_thread_socket_unix;
|
||||
s->peek = peek_socket_unix;
|
||||
s->verify = verify_ok;
|
||||
s->cleanup = socket_unix_cleanup;
|
||||
s->except_selected = true;
|
||||
s->except_ready = false;
|
||||
/* FIXME: Is this right? */
|
||||
s->except_ready = saw_shutdown ();
|
||||
grab_admin_pkt ();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,15 @@ struct select_socket_info: public select_info
|
||||
select_socket_info (): select_info (), num_w4 (0), ser_num (0), w4 (NULL) {}
|
||||
};
|
||||
|
||||
#ifdef __WITH_AF_UNIX
|
||||
|
||||
struct select_socket_unix_info: public select_info
|
||||
{
|
||||
select_socket_unix_info (): select_info () {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class select_stuff
|
||||
{
|
||||
public:
|
||||
@ -107,6 +116,10 @@ public:
|
||||
select_fifo_info *device_specific_fifo;
|
||||
select_socket_info *device_specific_socket;
|
||||
|
||||
#ifdef __WITH_AF_UNIX
|
||||
select_socket_unix_info *device_specific_socket_unix;
|
||||
#endif
|
||||
|
||||
bool test_and_set (int, fd_set *, fd_set *, fd_set *);
|
||||
int poll (fd_set *, fd_set *, fd_set *);
|
||||
wait_states wait (fd_set *, fd_set *, fd_set *, LONGLONG);
|
||||
@ -119,6 +132,9 @@ public:
|
||||
device_specific_ptys (NULL),
|
||||
device_specific_fifo (NULL),
|
||||
device_specific_socket (NULL)
|
||||
#ifdef __WITH_AF_UNIX
|
||||
, device_specific_socket_unix (NULL)
|
||||
#endif
|
||||
{}
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user