[7/8] network: Try to load WSAPoll dynamically

Message ID 1340712758-65898-7-git-send-email-martin@martin.st
State Deferred
Headers show

Commit Message

Martin Storsjö June 26, 2012, 12:12 p.m.
This gives the advantage of using this function (instead of the
emulation via select) on systems where it is available, while
retaining compatibility with systems that do not have it.

This requires making our fallback pollfd struct and constants
match what windows would use, so that a build that doesn't have
the windows pollfd definition available at build time would work
if the WSAPoll function is loaded at runtime.
---
 libavformat/network.c    |   13 +++++++++++++
 libavformat/network.h    |    3 +++
 libavformat/os_support.c |    3 +++
 libavformat/os_support.h |   24 ++++++++++++++----------
 4 files changed, 33 insertions(+), 10 deletions(-)

Comments

Mans Rullgard June 26, 2012, 2:41 p.m. | #1
Martin Storsjö <martin@martin.st> writes:

> This gives the advantage of using this function (instead of the
> emulation via select) on systems where it is available, while
> retaining compatibility with systems that do not have it.
>
> This requires making our fallback pollfd struct and constants
> match what windows would use, so that a build that doesn't have
> the windows pollfd definition available at build time would work
> if the WSAPoll function is loaded at runtime.
> ---
>  libavformat/network.c    |   13 +++++++++++++
>  libavformat/network.h    |    3 +++
>  libavformat/os_support.c |    3 +++
>  libavformat/os_support.h |   24 ++++++++++++++----------
>  4 files changed, 33 insertions(+), 10 deletions(-)

Is this really worth the complexity?  I doubt we use poll() in a
performance-sensitive way anywhere.
Martin Storsjö June 26, 2012, 7:42 p.m. | #2
On Tue, 26 Jun 2012, Måns Rullgård wrote:

> Martin Storsjö <martin@martin.st> writes:
>
>> This gives the advantage of using this function (instead of the
>> emulation via select) on systems where it is available, while
>> retaining compatibility with systems that do not have it.
>>
>> This requires making our fallback pollfd struct and constants
>> match what windows would use, so that a build that doesn't have
>> the windows pollfd definition available at build time would work
>> if the WSAPoll function is loaded at runtime.
>> ---
>>  libavformat/network.c    |   13 +++++++++++++
>>  libavformat/network.h    |    3 +++
>>  libavformat/os_support.c |    3 +++
>>  libavformat/os_support.h |   24 ++++++++++++++----------
>>  4 files changed, 33 insertions(+), 10 deletions(-)
>
> Is this really worth the complexity?  I doubt we use poll() in a
> performance-sensitive way anywhere.

I'm not sure. We do however call poll() once before each read() for TCP 
for instance.

// Martin
Mans Rullgard June 26, 2012, 7:50 p.m. | #3
Martin Storsjö <martin@martin.st> writes:

> On Tue, 26 Jun 2012, Måns Rullgård wrote:
>
>> Martin Storsjö <martin@martin.st> writes:
>>
>>> This gives the advantage of using this function (instead of the
>>> emulation via select) on systems where it is available, while
>>> retaining compatibility with systems that do not have it.
>>>
>>> This requires making our fallback pollfd struct and constants
>>> match what windows would use, so that a build that doesn't have
>>> the windows pollfd definition available at build time would work
>>> if the WSAPoll function is loaded at runtime.
>>> ---
>>>  libavformat/network.c    |   13 +++++++++++++
>>>  libavformat/network.h    |    3 +++
>>>  libavformat/os_support.c |    3 +++
>>>  libavformat/os_support.h |   24 ++++++++++++++----------
>>>  4 files changed, 33 insertions(+), 10 deletions(-)
>>
>> Is this really worth the complexity?  I doubt we use poll() in a
>> performance-sensitive way anywhere.
>
> I'm not sure. We do however call poll() once before each read() for
> TCP for instance.

Yes, but only on one file descriptor.  select() can still perform badly
if this file descriptor has a very large value, but is that really very
likely, especially on a system that doesn't have poll()?
Martin Storsjö June 27, 2012, 9:05 a.m. | #4
On Tue, 26 Jun 2012, Måns Rullgård wrote:

> Martin Storsjö <martin@martin.st> writes:
>
>> On Tue, 26 Jun 2012, Måns Rullgård wrote:
>>
>>> Martin Storsjö <martin@martin.st> writes:
>>>
>>>> This gives the advantage of using this function (instead of the
>>>> emulation via select) on systems where it is available, while
>>>> retaining compatibility with systems that do not have it.
>>>>
>>>> This requires making our fallback pollfd struct and constants
>>>> match what windows would use, so that a build that doesn't have
>>>> the windows pollfd definition available at build time would work
>>>> if the WSAPoll function is loaded at runtime.
>>>> ---
>>>>  libavformat/network.c    |   13 +++++++++++++
>>>>  libavformat/network.h    |    3 +++
>>>>  libavformat/os_support.c |    3 +++
>>>>  libavformat/os_support.h |   24 ++++++++++++++----------
>>>>  4 files changed, 33 insertions(+), 10 deletions(-)
>>>
>>> Is this really worth the complexity?  I doubt we use poll() in a
>>> performance-sensitive way anywhere.
>>
>> I'm not sure. We do however call poll() once before each read() for
>> TCP for instance.
>
> Yes, but only on one file descriptor.  select() can still perform badly
> if this file descriptor has a very large value, but is that really very
> likely, especially on a system that doesn't have poll()?

No idea. IIRC the windows select fdset implementation isn't bitfield 
based, so there might not be that much an issue with it at all.

Anyway, this (and the following ones) dropped for now.

// Martin

Patch

diff --git a/libavformat/network.c b/libavformat/network.c
index c2f7a9b..c702214 100644
--- a/libavformat/network.c
+++ b/libavformat/network.c
@@ -121,6 +121,12 @@  void ff_tls_deinit(void)
 
 int ff_network_inited_globally;
 
+#if HAVE_WINSOCK2_H
+static int ff_winsock_ptrs_loaded;
+int (WSAAPI *ff_wsapoll_ptr)(struct pollfd *fds, unsigned long nfds,
+                             int timeout);
+#endif
+
 int ff_network_init(void)
 {
 #if HAVE_WINSOCK2_H
@@ -135,6 +141,13 @@  int ff_network_init(void)
 #if HAVE_WINSOCK2_H
     if (WSAStartup(MAKEWORD(1,1), &wsaData))
         return 0;
+    if (!ff_winsock_ptrs_loaded && ff_network_inited_globally) {
+        /* Only do this init if we're called from avformat_network_init,
+         * which should be done before spawning any threads. */
+        HMODULE ws2mod = GetModuleHandle("ws2_32.dll");
+        ff_wsapoll_ptr = GetProcAddress(ws2mod, "WSAPoll");
+        ff_winsock_ptrs_loaded = 1;
+    }
 #endif
     return 1;
 }
diff --git a/libavformat/network.h b/libavformat/network.h
index 3724aa2..8fb7a82 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -51,6 +51,9 @@ 
 #define setsockopt(a, b, c, d, e) setsockopt(a, b, c, (const char*) d, e)
 
 int ff_neterrno(void);
+
+extern int (WSAAPI *ff_wsapoll_ptr)(struct pollfd *fds, unsigned long nfds,
+                                    int timeout);
 #else
 #include <sys/types.h>
 #include <sys/socket.h>
diff --git a/libavformat/os_support.c b/libavformat/os_support.c
index 04e5f9c..9ef63eb 100644
--- a/libavformat/os_support.c
+++ b/libavformat/os_support.c
@@ -284,6 +284,9 @@  int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout)
     int rc;
 
 #if HAVE_WINSOCK2_H
+    if (ff_wsapoll_ptr)
+        return ff_wsapoll_ptr(fds, numfds, timeout);
+
     if (numfds >= FD_SETSIZE) {
         errno = EINVAL;
         return -1;
diff --git a/libavformat/os_support.h b/libavformat/os_support.h
index 04f22d2..1afdd38 100644
--- a/libavformat/os_support.h
+++ b/libavformat/os_support.h
@@ -83,24 +83,28 @@  typedef unsigned long nfds_t;
 #endif
 #if !HAVE_STRUCT_POLLFD
 struct pollfd {
+#if HAVE_WINSOCK2_H
+    SOCKET fd;
+#else
     int fd;
+#endif
     short events;  /* events to look for */
     short revents; /* events that occurred */
 };
 
 /* events & revents */
-#define POLLIN     0x0001  /* any readable data available */
-#define POLLOUT    0x0002  /* file descriptor is writeable */
-#define POLLRDNORM POLLIN
-#define POLLWRNORM POLLOUT
-#define POLLRDBAND 0x0008  /* priority readable data */
-#define POLLWRBAND 0x0010  /* priority data can be written */
-#define POLLPRI    0x0020  /* high priority readable data */
+#define POLLIN     (POLLRDNORM | POLLRDBAND) /* any readable data available */
+#define POLLOUT    (POLLWRNORM) /* file descriptor is writeable */
+#define POLLRDNORM 0x0100
+#define POLLWRNORM 0x0010
+#define POLLRDBAND 0x0200  /* priority readable data */
+#define POLLWRBAND 0x0020  /* priority data can be written */
+#define POLLPRI    0x0400  /* high priority readable data */
 
 /* revents only */
-#define POLLERR    0x0004  /* errors pending */
-#define POLLHUP    0x0080  /* disconnected */
-#define POLLNVAL   0x1000  /* invalid file descriptor */
+#define POLLERR    0x0001  /* errors pending */
+#define POLLHUP    0x0002  /* disconnected */
+#define POLLNVAL   0x0004  /* invalid file descriptor */
 #endif