Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
VLC
Manage
Activity
Members
Labels
Plan
Issues
4k
Issue boards
Milestones
Code
Merge requests
456
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Analyze
Contributor analytics
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
VideoLAN
VLC
Commits
74337dd2
Commit
74337dd2
authored
9 years ago
by
Rémi Denis-Courmont
Browse files
Options
Downloads
Patches
Plain Diff
compat: reimplement and make poll() alertable on Windows
parent
80170ba7
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
compat/poll.c
+148
-53
148 additions, 53 deletions
compat/poll.c
with
148 additions
and
53 deletions
compat/poll.c
+
148
−
53
View file @
74337dd2
...
...
@@ -26,41 +26,14 @@
#include
<string.h>
#include
<errno.h>
#ifdef _WIN32
# ifdef FD_SETSIZE
/* Too late for #undef FD_SETSIZE to work: fd_set is already defined. */
# error Header inclusion order compromised!
# endif
# define FD_SETSIZE 0
# include <winsock2.h>
#else
#ifndef _WIN32
# include <sys/time.h>
# include <sys/select.h>
# include <fcntl.h>
#endif
int
(
poll
)
(
struct
pollfd
*
fds
,
unsigned
nfds
,
int
timeout
)
{
#ifdef _WIN32
size_t
setsize
=
sizeof
(
fd_set
)
+
nfds
*
sizeof
(
SOCKET
);
fd_set
*
rdset
=
malloc
(
setsize
);
fd_set
*
wrset
=
malloc
(
setsize
);
fd_set
*
exset
=
malloc
(
setsize
);
if
(
rdset
==
NULL
||
wrset
==
NULL
||
exset
==
NULL
)
{
free
(
rdset
);
free
(
wrset
);
free
(
exset
);
errno
=
ENOMEM
;
return
-
1
;
}
/* Winsock FD_SET uses FD_SETSIZE in its expansion */
# undef FD_SETSIZE
# define FD_SETSIZE (nfds)
#else
fd_set
rdset
[
1
],
wrset
[
1
],
exset
[
1
];
#endif
struct
timeval
tv
=
{
0
,
0
};
int
val
=
-
1
;
...
...
@@ -81,22 +54,12 @@ int (poll) (struct pollfd *fds, unsigned nfds, int timeout)
* default, such that it is quite feasible to get fd >= FD_SETSIZE.
* The next instructions will result in a buffer overflow if run on
* a POSIX system, and the later FD_ISSET would perform an undefined
* memory read.
*
* With Winsock, fd_set is a table of integers. This is awfully slow.
* However, FD_SET and FD_ISSET silently and safely discard excess
* entries. Here, overflow cannot happen anyway: fd_set of adequate
* size are allocated.
* Note that Vista has a much nicer WSAPoll(), but Mingw does not
* support it yet.
*/
#ifndef _WIN32
* memory read. */
if
((
unsigned
)
fd
>=
FD_SETSIZE
)
{
errno
=
EINVAL
;
return
-
1
;
}
#endif
if
(
fds
[
i
].
events
&
POLLRDNORM
)
FD_SET
(
fd
,
rdset
);
if
(
fds
[
i
].
events
&
POLLWRNORM
)
...
...
@@ -116,22 +79,13 @@ int (poll) (struct pollfd *fds, unsigned nfds, int timeout)
(
timeout
>=
0
)
?
&
tv
:
NULL
);
if
(
val
==
-
1
)
{
#ifndef _WIN32
if
(
errno
!=
EBADF
)
#else
if
(
WSAGetLastError
()
!=
WSAENOTSOCK
)
#endif
return
-
1
;
val
=
0
;
for
(
unsigned
i
=
0
;
i
<
nfds
;
i
++
)
#ifndef _WIN32
if
(
fcntl
(
fds
[
i
].
fd
,
F_GETFD
)
==
-
1
)
#else
if
(
getsockopt
(
fds
[
i
].
fd
,
SOL_SOCKET
,
SO_REUSEADDR
,
&
(
DWORD
){
0
},
&
(
int
){
sizeof
(
DWORD
)
})
!=
0
)
#endif
{
fds
[
i
].
revents
=
POLLNVAL
;
val
++
;
...
...
@@ -149,10 +103,151 @@ int (poll) (struct pollfd *fds, unsigned nfds, int timeout)
|
(
FD_ISSET
(
fd
,
wrset
)
?
POLLWRNORM
:
0
)
|
(
FD_ISSET
(
fd
,
exset
)
?
POLLPRI
:
0
);
}
#ifdef _WIN32
free
(
exset
);
free
(
wrset
);
free
(
rdset
);
#endif
return
val
;
}
#else
# include <windows.h>
# include <winsock2.h>
int
poll
(
struct
pollfd
*
fds
,
unsigned
nfds
,
int
timeout
)
{
DWORD
to
=
(
timeout
>=
0
)
?
(
DWORD
)
timeout
:
INFINITE
;
if
(
nfds
==
0
)
{
/* WSAWaitForMultipleEvents() does not allow zero events */
if
(
SleepEx
(
to
,
TRUE
))
{
errno
=
EINTR
;
return
-
1
;
}
return
0
;
}
WSAEVENT
*
evts
=
malloc
(
nfds
*
sizeof
(
WSAEVENT
));
if
(
evts
==
NULL
)
return
-
1
;
/* ENOMEM */
DWORD
ret
=
WSA_WAIT_FAILED
;
for
(
unsigned
i
=
0
;
i
<
nfds
;
i
++
)
{
SOCKET
fd
=
fds
[
i
].
fd
;
long
mask
=
FD_CLOSE
;
fd_set
rdset
,
wrset
,
exset
;
FD_ZERO
(
&
rdset
);
FD_ZERO
(
&
wrset
);
FD_ZERO
(
&
exset
);
FD_SET
(
fd
,
&
exset
);
if
(
fds
[
i
].
events
&
POLLRDNORM
)
{
mask
|=
FD_READ
|
FD_ACCEPT
;
FD_SET
(
fd
,
&
rdset
);
}
if
(
fds
[
i
].
events
&
POLLWRNORM
)
{
mask
|=
FD_WRITE
|
FD_CONNECT
;
FD_SET
(
fd
,
&
wrset
);
}
if
(
fds
[
i
].
events
&
POLLPRI
)
mask
|=
FD_OOB
;
fds
[
i
].
revents
=
0
;
evts
[
i
]
=
WSACreateEvent
();
if
(
evts
[
i
]
==
WSA_INVALID_EVENT
)
{
while
(
i
>
0
)
WSACloseEvent
(
evts
[
--
i
]);
free
(
evts
);
errno
=
ENOMEM
;
return
-
1
;
}
if
(
WSAEventSelect
(
fds
[
i
].
fd
,
evts
[
i
],
mask
)
&&
WSAGetLastError
()
==
WSAENOTSOCK
)
fds
[
i
].
revents
|=
POLLNVAL
;
struct
timeval
tv
=
{
0
,
0
};
/* By its horrible design, WSAEnumNetworkEvents() only enumerates
* events that were not already signaled (i.e. it is edge-triggered).
* WSAPoll() would be better in this respect, but worse in others.
* So use WSAEnumNetworkEvents() after manually checking for pending
* events. */
if
(
select
(
0
,
&
rdset
,
&
wrset
,
&
exset
,
&
tv
)
>
0
)
{
if
(
FD_ISSET
(
fd
,
&
rdset
))
fds
[
i
].
revents
|=
fds
[
i
].
events
&
POLLRDNORM
;
if
(
FD_ISSET
(
fd
,
&
wrset
))
fds
[
i
].
revents
|=
fds
[
i
].
events
&
POLLWRNORM
;
if
(
FD_ISSET
(
fd
,
&
exset
))
/* To add pain to injury, POLLERR and POLLPRI cannot be
* distinguished here. */
fds
[
i
].
revents
|=
POLLERR
|
(
fds
[
i
].
events
&
POLLPRI
);
}
if
(
fds
[
i
].
revents
!=
0
&&
ret
==
WSA_WAIT_FAILED
)
ret
=
WSA_WAIT_EVENT_0
+
i
;
}
if
(
ret
==
WSA_WAIT_FAILED
)
ret
=
WSAWaitForMultipleEvents
(
nfds
,
evts
,
FALSE
,
to
,
TRUE
);
unsigned
count
=
0
;
for
(
unsigned
i
=
0
;
i
<
nfds
;
i
++
)
{
WSANETWORKEVENTS
ne
;
if
(
WSAEnumNetworkEvents
(
fds
[
i
].
fd
,
evts
[
i
],
&
ne
))
memset
(
&
ne
,
0
,
sizeof
(
ne
));
WSACloseEvent
(
evts
[
i
]);
if
(
ne
.
lNetworkEvents
&
FD_CONNECT
)
{
fds
[
i
].
revents
|=
POLLWRNORM
;
if
(
ne
.
iErrorCode
[
FD_CONNECT_BIT
]
!=
0
)
fds
[
i
].
revents
|=
POLLERR
;
}
if
(
ne
.
lNetworkEvents
&
FD_CLOSE
)
{
fds
[
i
].
revents
|=
(
fds
[
i
].
events
&
POLLRDNORM
)
|
POLLHUP
;
if
(
ne
.
iErrorCode
[
FD_CLOSE_BIT
]
!=
0
)
fds
[
i
].
revents
|=
POLLERR
;
}
if
(
ne
.
lNetworkEvents
&
FD_ACCEPT
)
{
fds
[
i
].
revents
|=
POLLRDNORM
;
if
(
ne
.
iErrorCode
[
FD_ACCEPT_BIT
]
!=
0
)
fds
[
i
].
revents
|=
POLLERR
;
}
if
(
ne
.
lNetworkEvents
&
FD_OOB
)
{
fds
[
i
].
revents
|=
POLLPRI
;
if
(
ne
.
iErrorCode
[
FD_OOB_BIT
]
!=
0
)
fds
[
i
].
revents
|=
POLLERR
;
}
if
(
ne
.
lNetworkEvents
&
FD_READ
)
{
fds
[
i
].
revents
|=
POLLRDNORM
;
if
(
ne
.
iErrorCode
[
FD_READ_BIT
]
!=
0
)
fds
[
i
].
revents
|=
POLLERR
;
}
if
(
ne
.
lNetworkEvents
&
FD_WRITE
)
{
fds
[
i
].
revents
|=
POLLWRNORM
;
if
(
ne
.
iErrorCode
[
FD_WRITE_BIT
]
!=
0
)
fds
[
i
].
revents
|=
POLLERR
;
}
count
+=
fds
[
i
].
revents
!=
0
;
}
free
(
evts
);
if
(
count
==
0
&&
ret
==
WSA_WAIT_IO_COMPLETION
)
{
errno
=
EINTR
;
return
-
1
;
}
return
count
;
}
#endif
This diff is collapsed.
Click to expand it.
Rémi Denis-Courmont
@Courmisch
mentioned in issue
#5470 (closed)
·
4 years ago
mentioned in issue
#5470 (closed)
mentioned in issue #5470
Toggle commit list
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment