watcher: Add Windows support
Instead of a pipe we use a TCP socketpair (can't select() a _pipe()), and Windsock2 send/recv functions instead of read/write. Currently supported (and required) are file descriptors provided by Winsock only; we might use a separate mechanism for traditional file handles if required (or switch to Windows events and WaitForMultipleObjects) for a future version.
This commit is contained in:
@@ -24,7 +24,9 @@
|
|||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#ifndef WIN32
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
#endif
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
typedef struct private_watcher_t private_watcher_t;
|
typedef struct private_watcher_t private_watcher_t;
|
||||||
@@ -119,7 +121,14 @@ static void update(private_watcher_t *this)
|
|||||||
this->pending = TRUE;
|
this->pending = TRUE;
|
||||||
if (this->notify[1] != -1)
|
if (this->notify[1] != -1)
|
||||||
{
|
{
|
||||||
ignore_result(write(this->notify[1], buf, sizeof(buf)));
|
#ifdef WIN32
|
||||||
|
if (send(this->notify[1], buf, sizeof(buf), 0) == -1)
|
||||||
|
#else
|
||||||
|
if (write(this->notify[1], buf, sizeof(buf)) == -1)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
DBG1(DBG_JOB, "notifying watcher failed: %s", strerror(errno));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,21 +302,40 @@ static job_requeue_t watch(private_watcher_t *this)
|
|||||||
{
|
{
|
||||||
char buf[1];
|
char buf[1];
|
||||||
bool old;
|
bool old;
|
||||||
|
ssize_t len;
|
||||||
job_t *job;
|
job_t *job;
|
||||||
|
|
||||||
DBG2(DBG_JOB, "watcher going to select()");
|
DBG2(DBG_JOB, "watcher going to select()");
|
||||||
thread_cleanup_push((void*)activate_all, this);
|
thread_cleanup_push((void*)activate_all, this);
|
||||||
old = thread_cancelability(TRUE);
|
old = thread_cancelability(TRUE);
|
||||||
|
|
||||||
res = select(maxfd + 1, &rd, &wr, &ex, NULL);
|
res = select(maxfd + 1, &rd, &wr, &ex, NULL);
|
||||||
thread_cancelability(old);
|
thread_cancelability(old);
|
||||||
thread_cleanup_pop(FALSE);
|
thread_cleanup_pop(FALSE);
|
||||||
|
|
||||||
if (res > 0)
|
if (res > 0)
|
||||||
{
|
{
|
||||||
if (this->notify[0] != -1 && FD_ISSET(this->notify[0], &rd))
|
if (this->notify[0] != -1 && FD_ISSET(this->notify[0], &rd))
|
||||||
{
|
{
|
||||||
DBG2(DBG_JOB, "watcher got notification, rebuilding");
|
while (TRUE)
|
||||||
while (read(this->notify[0], buf, sizeof(buf)) > 0);
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
len = recv(this->notify[0], buf, sizeof(buf), 0);
|
||||||
|
#else
|
||||||
|
len = read(this->notify[0], buf, sizeof(buf));
|
||||||
|
#endif
|
||||||
|
if (len == -1)
|
||||||
|
{
|
||||||
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||||
|
{
|
||||||
|
DBG1(DBG_JOB, "reading watcher notify failed: %s",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
this->pending = FALSE;
|
this->pending = FALSE;
|
||||||
|
DBG2(DBG_JOB, "watcher got notification, rebuilding");
|
||||||
return JOB_REQUEUE_DIRECT;
|
return JOB_REQUEUE_DIRECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,13 +474,60 @@ METHOD(watcher_t, destroy, void,
|
|||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create notify pipe with a TCP socketpair
|
||||||
|
*/
|
||||||
|
static bool create_notify(private_watcher_t *this)
|
||||||
|
{
|
||||||
|
u_long on = 1;
|
||||||
|
|
||||||
|
if (socketpair(AF_INET, SOCK_STREAM, 0, this->notify) == 0)
|
||||||
|
{
|
||||||
|
/* use non-blocking I/O on read-end of notify pipe */
|
||||||
|
if (ioctlsocket(this->notify[0], FIONBIO, &on) == 0)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
DBG1(DBG_LIB, "setting watcher notify pipe read-end non-blocking "
|
||||||
|
"failed: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* !WIN32 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a notify pipe with a one-directional pipe
|
||||||
|
*/
|
||||||
|
static bool create_notify(private_watcher_t *this)
|
||||||
|
{
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
if (pipe(this->notify) == 0)
|
||||||
|
{
|
||||||
|
/* use non-blocking I/O on read-end of notify pipe */
|
||||||
|
flags = fcntl(this->notify[0], F_GETFL);
|
||||||
|
if (flags != -1 &&
|
||||||
|
fcntl(this->notify[0], F_SETFL, flags | O_NONBLOCK) != -1)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
DBG1(DBG_LIB, "setting watcher notify pipe read-end non-blocking "
|
||||||
|
"failed: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !WIN32 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See header
|
* See header
|
||||||
*/
|
*/
|
||||||
watcher_t *watcher_create()
|
watcher_t *watcher_create()
|
||||||
{
|
{
|
||||||
private_watcher_t *this;
|
private_watcher_t *this;
|
||||||
int flags;
|
|
||||||
|
|
||||||
INIT(this,
|
INIT(this,
|
||||||
.public = {
|
.public = {
|
||||||
@@ -467,18 +542,7 @@ watcher_t *watcher_create()
|
|||||||
.notify = {-1, -1},
|
.notify = {-1, -1},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (pipe(this->notify) == 0)
|
if (!create_notify(this))
|
||||||
{
|
|
||||||
/* use non-blocking I/O on read-end of notify pipe */
|
|
||||||
flags = fcntl(this->notify[0], F_GETFL);
|
|
||||||
if (flags == -1 ||
|
|
||||||
fcntl(this->notify[0], F_SETFL, flags | O_NONBLOCK) == -1)
|
|
||||||
{
|
|
||||||
DBG1(DBG_LIB, "setting watcher notify pipe read-end non-blocking "
|
|
||||||
"failed: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
DBG1(DBG_LIB, "creating watcher notify pipe failed: %s",
|
DBG1(DBG_LIB, "creating watcher notify pipe failed: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
|||||||
Reference in New Issue
Block a user