Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
414b31bc
Commit
414b31bc
authored
Jun 20, 2021
by
Zebediah Figura
Committed by
Alexandre Julliard
Jun 21, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ws2_32: Reimplement select() on top of IOCTL_AFD_POLL.
Signed-off-by:
Zebediah Figura
<
z.figura12@gmail.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
639a4cab
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
109 additions
and
208 deletions
+109
-208
socket.c
dlls/ws2_32/socket.c
+100
-205
sock.c
dlls/ws2_32/tests/sock.c
+9
-1
ws2_32_private.h
dlls/ws2_32/ws2_32_private.h
+0
-2
No files found.
dlls/ws2_32/socket.c
View file @
414b31bc
...
...
@@ -841,7 +841,6 @@ static void free_per_thread_data(void)
HeapFree
(
GetProcessHeap
(),
0
,
ptb
->
he_buffer
);
HeapFree
(
GetProcessHeap
(),
0
,
ptb
->
se_buffer
);
HeapFree
(
GetProcessHeap
(),
0
,
ptb
->
pe_buffer
);
HeapFree
(
GetProcessHeap
(),
0
,
ptb
->
fd_cache
);
HeapFree
(
GetProcessHeap
(),
0
,
ptb
);
NtCurrentTeb
()
->
WinSockData
=
NULL
;
...
...
@@ -3216,246 +3215,142 @@ int WINAPI WS_recvfrom(SOCKET s, char *buf, INT len, int flags,
return
n
;
}
/* allocate a poll array for the corresponding fd sets */
static
struct
pollfd
*
fd_sets_to_poll
(
const
WS_fd_set
*
readfds
,
const
WS_fd_set
*
writefds
,
const
WS_fd_set
*
exceptfds
,
int
*
count_ptr
)
/* as FD_SET(), but returns 1 if the fd was added, 0 otherwise */
static
int
add_fd_to_set
(
SOCKET
fd
,
struct
WS_fd_set
*
set
)
{
unsigned
int
i
,
j
=
0
,
count
=
0
;
struct
pollfd
*
fds
;
struct
per_thread_data
*
ptb
=
get_per_thread_data
();
if
(
readfds
)
count
+=
readfds
->
fd_count
;
if
(
writefds
)
count
+=
writefds
->
fd_count
;
if
(
exceptfds
)
count
+=
exceptfds
->
fd_count
;
*
count_ptr
=
count
;
if
(
!
count
)
{
SetLastError
(
WSAEINVAL
);
return
NULL
;
}
unsigned
int
i
;
/* check if the cache can hold all descriptors, if not do the resizing */
if
(
ptb
->
fd_count
<
count
)
for
(
i
=
0
;
i
<
set
->
fd_count
;
++
i
)
{
if
(
!
(
fds
=
HeapAlloc
(
GetProcessHeap
(),
0
,
count
*
sizeof
(
fds
[
0
]))))
{
SetLastError
(
ERROR_NOT_ENOUGH_MEMORY
);
return
NULL
;
}
HeapFree
(
GetProcessHeap
(),
0
,
ptb
->
fd_cache
);
ptb
->
fd_cache
=
fds
;
ptb
->
fd_count
=
count
;
if
(
set
->
fd_array
[
i
]
==
fd
)
return
0
;
}
else
fds
=
ptb
->
fd_cache
;
if
(
readfds
)
for
(
i
=
0
;
i
<
readfds
->
fd_count
;
i
++
,
j
++
)
{
fds
[
j
].
fd
=
get_sock_fd
(
readfds
->
fd_array
[
i
],
FILE_READ_DATA
,
NULL
);
if
(
fds
[
j
].
fd
==
-
1
)
goto
failed
;
fds
[
j
].
revents
=
0
;
if
(
is_fd_bound
(
fds
[
j
].
fd
,
NULL
,
NULL
)
==
1
)
if
(
set
->
fd_count
<
WS_FD_SETSIZE
)
{
fds
[
j
].
events
=
POLLIN
;
}
else
{
release_sock_fd
(
readfds
->
fd_array
[
i
],
fds
[
j
].
fd
);
fds
[
j
].
fd
=
-
1
;
fds
[
j
].
events
=
0
;
}
}
if
(
writefds
)
for
(
i
=
0
;
i
<
writefds
->
fd_count
;
i
++
,
j
++
)
{
fds
[
j
].
fd
=
get_sock_fd
(
writefds
->
fd_array
[
i
],
FILE_WRITE_DATA
,
NULL
);
if
(
fds
[
j
].
fd
==
-
1
)
goto
failed
;
fds
[
j
].
revents
=
0
;
if
(
is_fd_bound
(
fds
[
j
].
fd
,
NULL
,
NULL
)
==
1
||
_get_fd_type
(
fds
[
j
].
fd
)
==
SOCK_DGRAM
)
{
fds
[
j
].
events
=
POLLOUT
;
}
else
{
release_sock_fd
(
writefds
->
fd_array
[
i
],
fds
[
j
].
fd
);
fds
[
j
].
fd
=
-
1
;
fds
[
j
].
events
=
0
;
}
set
->
fd_array
[
set
->
fd_count
++
]
=
fd
;
return
1
;
}
if
(
exceptfds
)
for
(
i
=
0
;
i
<
exceptfds
->
fd_count
;
i
++
,
j
++
)
{
fds
[
j
].
fd
=
get_sock_fd
(
exceptfds
->
fd_array
[
i
],
0
,
NULL
);
if
(
fds
[
j
].
fd
==
-
1
)
goto
failed
;
fds
[
j
].
revents
=
0
;
if
(
is_fd_bound
(
fds
[
j
].
fd
,
NULL
,
NULL
)
==
1
)
{
int
oob_inlined
=
0
;
socklen_t
olen
=
sizeof
(
oob_inlined
);
fds
[
j
].
events
=
POLLHUP
;
/* Check if we need to test for urgent data or not */
getsockopt
(
fds
[
j
].
fd
,
SOL_SOCKET
,
SO_OOBINLINE
,
(
char
*
)
&
oob_inlined
,
&
olen
);
if
(
!
oob_inlined
)
fds
[
j
].
events
|=
POLLPRI
;
}
else
{
release_sock_fd
(
exceptfds
->
fd_array
[
i
],
fds
[
j
].
fd
);
fds
[
j
].
fd
=
-
1
;
fds
[
j
].
events
=
0
;
}
}
return
fds
;
failed:
count
=
j
;
j
=
0
;
if
(
readfds
)
for
(
i
=
0
;
i
<
readfds
->
fd_count
&&
j
<
count
;
i
++
,
j
++
)
if
(
fds
[
j
].
fd
!=
-
1
)
release_sock_fd
(
readfds
->
fd_array
[
i
],
fds
[
j
].
fd
);
if
(
writefds
)
for
(
i
=
0
;
i
<
writefds
->
fd_count
&&
j
<
count
;
i
++
,
j
++
)
if
(
fds
[
j
].
fd
!=
-
1
)
release_sock_fd
(
writefds
->
fd_array
[
i
],
fds
[
j
].
fd
);
if
(
exceptfds
)
for
(
i
=
0
;
i
<
exceptfds
->
fd_count
&&
j
<
count
;
i
++
,
j
++
)
if
(
fds
[
j
].
fd
!=
-
1
)
release_sock_fd
(
exceptfds
->
fd_array
[
i
],
fds
[
j
].
fd
);
return
NULL
;
return
0
;
}
/* release the file descriptor obtained in fd_sets_to_poll */
/* must be called with the original fd_set arrays, before calling get_poll_results */
static
void
release_poll_fds
(
const
WS_fd_set
*
readfds
,
const
WS_fd_set
*
writefds
,
const
WS_fd_set
*
exceptfds
,
struct
pollfd
*
fds
)
/***********************************************************************
* select (ws2_32.18)
*/
int
WINAPI
WS_select
(
int
count
,
WS_fd_set
*
read_ptr
,
WS_fd_set
*
write_ptr
,
WS_fd_set
*
except_ptr
,
const
struct
WS_timeval
*
timeout
)
{
unsigned
int
i
,
j
=
0
;
char
buffer
[
offsetof
(
struct
afd_poll_params
,
sockets
[
WS_FD_SETSIZE
*
3
]
)]
=
{
0
};
struct
afd_poll_params
*
params
=
(
struct
afd_poll_params
*
)
buffer
;
struct
WS_fd_set
read
,
write
,
except
;
ULONG
params_size
,
i
,
j
;
SOCKET
poll_socket
=
0
;
IO_STATUS_BLOCK
io
;
HANDLE
sync_event
;
int
ret_count
=
0
;
NTSTATUS
status
;
TRACE
(
"read %p, write %p, except %p, timeout %p
\n
"
,
read_ptr
,
write_ptr
,
except_ptr
,
timeout
);
WS_FD_ZERO
(
&
read
);
WS_FD_ZERO
(
&
write
);
WS_FD_ZERO
(
&
except
);
if
(
read_ptr
)
read
=
*
read_ptr
;
if
(
write_ptr
)
write
=
*
write_ptr
;
if
(
except_ptr
)
except
=
*
except_ptr
;
if
(
readfds
)
if
(
!
(
sync_event
=
get_sync_event
()))
return
-
1
;
if
(
timeout
)
params
->
timeout
=
timeout
->
tv_sec
*
-
10000000
+
timeout
->
tv_usec
*
-
10
;
else
params
->
timeout
=
TIMEOUT_INFINITE
;
for
(
i
=
0
;
i
<
read
.
fd_count
;
++
i
)
{
for
(
i
=
0
;
i
<
readfds
->
fd_count
;
i
++
,
j
++
)
if
(
fds
[
j
].
fd
!=
-
1
)
release_sock_fd
(
readfds
->
fd_array
[
i
],
fds
[
j
].
fd
);
params
->
sockets
[
params
->
count
].
socket
=
read
.
fd_array
[
i
];
params
->
sockets
[
params
->
count
].
flags
=
AFD_POLL_READ
|
AFD_POLL_ACCEPT
|
AFD_POLL_HUP
;
++
params
->
count
;
poll_socket
=
read
.
fd_array
[
i
];
}
if
(
writefds
)
for
(
i
=
0
;
i
<
write
.
fd_count
;
++
i
)
{
for
(
i
=
0
;
i
<
writefds
->
fd_count
;
i
++
,
j
++
)
if
(
fds
[
j
].
fd
!=
-
1
)
release_sock_fd
(
writefds
->
fd_array
[
i
],
fds
[
j
].
fd
);
params
->
sockets
[
params
->
count
].
socket
=
write
.
fd_array
[
i
];
params
->
sockets
[
params
->
count
].
flags
=
AFD_POLL_WRITE
;
++
params
->
count
;
poll_socket
=
write
.
fd_array
[
i
];
}
if
(
exceptfds
)
{
for
(
i
=
0
;
i
<
exceptfds
->
fd_count
;
i
++
,
j
++
)
{
if
(
fds
[
j
].
fd
==
-
1
)
continue
;
release_sock_fd
(
exceptfds
->
fd_array
[
i
],
fds
[
j
].
fd
);
if
(
fds
[
j
].
revents
&
POLLHUP
)
for
(
i
=
0
;
i
<
except
.
fd_count
;
++
i
)
{
int
fd
=
get_sock_fd
(
exceptfds
->
fd_array
[
i
],
0
,
NULL
);
if
(
fd
!=
-
1
)
release_sock_fd
(
exceptfds
->
fd_array
[
i
],
fd
);
else
fds
[
j
].
revents
=
0
;
}
}
params
->
sockets
[
params
->
count
].
socket
=
except
.
fd_array
[
i
];
params
->
sockets
[
params
->
count
].
flags
=
AFD_POLL_OOB
|
AFD_POLL_CONNECT_ERR
;
++
params
->
count
;
poll_socket
=
except
.
fd_array
[
i
];
}
}
static
int
do_poll
(
struct
pollfd
*
pollfds
,
int
count
,
int
timeout
)
{
struct
timeval
tv1
,
tv2
;
int
ret
,
torig
=
timeout
;
if
(
timeout
>
0
)
gettimeofday
(
&
tv1
,
0
);
while
((
ret
=
poll
(
pollfds
,
count
,
timeout
))
<
0
)
if
(
!
params
->
count
)
{
if
(
errno
!=
EINTR
)
break
;
if
(
timeout
<
0
)
continue
;
if
(
timeout
==
0
)
return
0
;
SetLastError
(
WSAEINVAL
)
;
return
-
1
;
}
gettimeofday
(
&
tv2
,
0
);
params_size
=
offsetof
(
struct
afd_poll_params
,
sockets
[
params
->
count
]
);
tv2
.
tv_sec
-=
tv1
.
tv_sec
;
tv2
.
tv_usec
-=
tv1
.
tv_usec
;
if
(
tv2
.
tv_usec
<
0
)
status
=
NtDeviceIoControlFile
(
(
HANDLE
)
poll_socket
,
sync_event
,
NULL
,
NULL
,
&
io
,
IOCTL_AFD_POLL
,
params
,
params_size
,
params
,
params_size
)
;
if
(
status
==
STATUS_PENDING
)
{
tv2
.
tv_usec
+=
1000000
;
tv2
.
tv_sec
-=
1
;
}
timeout
=
torig
-
(
tv2
.
tv_sec
*
1000
)
-
(
tv2
.
tv_usec
+
999
)
/
1000
;
if
(
timeout
<=
0
)
return
0
;
if
(
WaitForSingleObject
(
sync_event
,
INFINITE
)
==
WAIT_FAILED
)
return
-
1
;
status
=
io
.
u
.
Status
;
}
return
ret
;
}
if
(
status
==
STATUS_TIMEOUT
)
status
=
STATUS_SUCCESS
;
if
(
!
status
)
{
/* pointers may alias, so clear them all first */
if
(
read_ptr
)
WS_FD_ZERO
(
read_ptr
);
if
(
write_ptr
)
WS_FD_ZERO
(
write_ptr
);
if
(
except_ptr
)
WS_FD_ZERO
(
except_ptr
);
/* map the poll results back into the Windows fd sets */
static
int
get_poll_results
(
WS_fd_set
*
readfds
,
WS_fd_set
*
writefds
,
WS_fd_set
*
exceptfds
,
const
struct
pollfd
*
fds
)
{
const
struct
pollfd
*
poll_writefds
=
fds
+
(
readfds
?
readfds
->
fd_count
:
0
);
const
struct
pollfd
*
poll_exceptfds
=
poll_writefds
+
(
writefds
?
writefds
->
fd_count
:
0
);
unsigned
int
i
,
k
,
total
=
0
;
for
(
i
=
0
;
i
<
params
->
count
;
++
i
)
{
unsigned
int
flags
=
params
->
sockets
[
i
].
flags
;
SOCKET
s
=
params
->
sockets
[
i
].
socket
;
if
(
readfds
)
for
(
j
=
0
;
j
<
read
.
fd_count
;
++
j
)
{
for
(
i
=
k
=
0
;
i
<
readfds
->
fd_count
;
i
++
)
if
(
read
.
fd_array
[
j
]
==
s
&&
(
flags
&
(
AFD_POLL_READ
|
AFD_POLL_ACCEPT
|
AFD_POLL_HUP
|
AFD_POLL_CLOSE
)))
{
if
(
fds
[
i
].
revents
||
(
readfds
==
writefds
&&
(
poll_writefds
[
i
].
revents
&
POLLOUT
)
&&
!
(
poll_writefds
[
i
].
revents
&
POLLHUP
))
||
(
readfds
==
exceptfds
&&
poll_exceptfds
[
i
].
revents
))
readfds
->
fd_array
[
k
++
]
=
readfds
->
fd_array
[
i
];
ret_count
+=
add_fd_to_set
(
s
,
read_ptr
);
flags
&=
~
AFD_POLL_CLOSE
;
}
readfds
->
fd_count
=
k
;
total
+=
k
;
}
if
(
writefds
&&
writefds
!=
readfds
)
if
(
flags
&
AFD_POLL_CLOSE
)
status
=
STATUS_INVALID_HANDLE
;
for
(
j
=
0
;
j
<
write
.
fd_count
;
++
j
)
{
for
(
i
=
k
=
0
;
i
<
writefds
->
fd_count
;
i
++
)
if
(
write
.
fd_array
[
j
]
==
s
&&
(
flags
&
AFD_POLL_WRITE
))
ret_count
+=
add_fd_to_set
(
s
,
write_ptr
);
}
for
(
j
=
0
;
j
<
except
.
fd_count
;
++
j
)
{
if
(((
poll_writefds
[
i
].
revents
&
POLLOUT
)
&&
!
(
poll_writefds
[
i
].
revents
&
POLLHUP
))
||
(
writefds
==
exceptfds
&&
poll_exceptfds
[
i
].
revents
))
writefds
->
fd_array
[
k
++
]
=
writefds
->
fd_array
[
i
];
if
(
except
.
fd_array
[
j
]
==
s
&&
(
flags
&
(
AFD_POLL_OOB
|
AFD_POLL_CONNECT_ERR
)))
ret_count
+=
add_fd_to_set
(
s
,
except_ptr
);
}
writefds
->
fd_count
=
k
;
total
+=
k
;
}
if
(
exceptfds
&&
exceptfds
!=
readfds
&&
exceptfds
!=
writefds
)
{
for
(
i
=
k
=
0
;
i
<
exceptfds
->
fd_count
;
i
++
)
if
(
poll_exceptfds
[
i
].
revents
)
exceptfds
->
fd_array
[
k
++
]
=
exceptfds
->
fd_array
[
i
];
exceptfds
->
fd_count
=
k
;
total
+=
k
;
}
return
total
;
}
/***********************************************************************
* select (WS2_32.18)
*/
int
WINAPI
WS_select
(
int
nfds
,
WS_fd_set
*
ws_readfds
,
WS_fd_set
*
ws_writefds
,
WS_fd_set
*
ws_exceptfds
,
const
struct
WS_timeval
*
ws_timeout
)
{
struct
pollfd
*
pollfds
;
int
count
,
ret
,
timeout
=
-
1
;
TRACE
(
"read %p, write %p, excp %p timeout %p
\n
"
,
ws_readfds
,
ws_writefds
,
ws_exceptfds
,
ws_timeout
);
if
(
!
(
pollfds
=
fd_sets_to_poll
(
ws_readfds
,
ws_writefds
,
ws_exceptfds
,
&
count
)))
return
SOCKET_ERROR
;
if
(
ws_timeout
)
timeout
=
(
ws_timeout
->
tv_sec
*
1000
)
+
(
ws_timeout
->
tv_usec
+
999
)
/
1000
;
ret
=
do_poll
(
pollfds
,
count
,
timeout
);
release_poll_fds
(
ws_readfds
,
ws_writefds
,
ws_exceptfds
,
pollfds
);
if
(
ret
==
-
1
)
SetLastError
(
wsaErrno
());
else
ret
=
get_poll_results
(
ws_readfds
,
ws_writefds
,
ws_exceptfds
,
pollfds
);
return
ret
;
SetLastError
(
NtStatusToWSAError
(
status
)
);
return
status
?
-
1
:
ret_count
;
}
...
...
dlls/ws2_32/tests/sock.c
View file @
414b31bc
...
...
@@ -3127,6 +3127,14 @@ static void test_select(void)
ret
=
select
(
0
,
&
readfds
,
&
writefds
,
&
exceptfds
,
&
select_timeout
);
ok
(
ret
==
1
,
"expected 1, got %d
\n
"
,
ret
);
ok
(
FD_ISSET
(
fdRead
,
&
readfds
),
"fdRead socket is not in the set
\n
"
);
ok
(
!
FD_ISSET
(
fdRead
,
&
exceptfds
),
"fdRead socket is in the set
\n
"
);
FD_ZERO_ALL
();
FD_SET_ALL
(
fdRead
);
ret
=
select
(
0
,
&
readfds
,
&
writefds
,
&
exceptfds
,
&
select_timeout
);
ok
(
ret
==
2
,
"expected 1, got %d
\n
"
,
ret
);
ok
(
FD_ISSET
(
fdRead
,
&
readfds
),
"fdRead socket is not in the set
\n
"
);
ok
(
FD_ISSET
(
fdRead
,
&
writefds
),
"fdRead socket is not in the set
\n
"
);
ok
(
!
FD_ISSET
(
fdRead
,
&
exceptfds
),
"fdRead socket is in the set
\n
"
);
ret
=
recv
(
fdRead
,
tmp_buf
,
sizeof
(
tmp_buf
),
0
);
ok
(
ret
==
4
,
"expected 4, got %d
\n
"
,
ret
);
ok
(
!
strcmp
(
tmp_buf
,
"1234"
),
"data received differs from sent
\n
"
);
...
...
@@ -3239,9 +3247,9 @@ static void test_select(void)
FD_SET
(
fdWrite
,
&
exceptfds
);
SetLastError
(
0xdeadbeef
);
ret
=
select
(
0
,
NULL
,
NULL
,
&
exceptfds
,
&
select_timeout
);
todo_wine
ok
(
ret
==
SOCKET_ERROR
,
"expected -1, got %d
\n
"
,
ret
);
ok
(
GetLastError
()
==
WSAENOTSOCK
,
"got %d
\n
"
,
GetLastError
());
ok
(
!
FD_ISSET
(
fdWrite
,
&
exceptfds
),
"fdWrite socket is in the set
\n
"
);
WaitForSingleObject
(
thread_handle
,
1000
);
closesocket
(
fdRead
);
...
...
dlls/ws2_32/ws2_32_private.h
View file @
414b31bc
...
...
@@ -190,8 +190,6 @@ struct per_thread_data
struct
WS_hostent
*
he_buffer
;
struct
WS_servent
*
se_buffer
;
struct
WS_protoent
*
pe_buffer
;
struct
pollfd
*
fd_cache
;
unsigned
int
fd_count
;
int
he_len
;
int
se_len
;
int
pe_len
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment