Commit e6c3041c authored by Michael Graff's avatar Michael Graff
Browse files

add file descriptor watching functions, Unix only.

parent 309a3b58
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: socket.h,v 1.62 2005/10/17 03:47:10 marka Exp $ */
/* $Id: socket.h,v 1.63 2005/12/06 16:54:49 explorer Exp $ */
#ifndef ISC_SOCKET_H
#define ISC_SOCKET_H 1
......@@ -143,7 +143,8 @@ struct isc_socket_connev {
typedef enum {
isc_sockettype_udp = 1,
isc_sockettype_tcp = 2,
isc_sockettype_unix = 3
isc_sockettype_unix = 3,
isc_sockettype_fdwatch = 4,
} isc_sockettype_t;
/*@{*/
......@@ -174,6 +175,14 @@ typedef enum {
#define ISC_SOCKFLAG_NORETRY 0x00000002 /*%< drop failed UDP sends */
/*@}*/
/*@{*/
/*!
* Flags for fdwatchcreate.
*/
#define ISC_SOCKFDWATCH_READ 0x00000001 /*%< watch for readable */
#define ISC_SOCKFDWATCH_WRITE 0x00000002 /*%< watch for writable */
/*@}*/
/***
*** Socket and Socket Manager Functions
***
......@@ -181,6 +190,45 @@ typedef enum {
*** those functions which return an isc_result.
***/
isc_result_t
isc_socket_fdwatchcreate(isc_socketmgr_t *manager,
int fd,
int flags,
isc_sockfdwatch_t callback,
void *cbarg,
isc_task_t *task,
isc_socket_t **socketp);
/*%<
* Create a new file descriptor watch socket managed by 'manager'.
*
* Note:
*
*\li 'fd' is the already-opened file descriptor.
*\li This function is not available on Windows.
*\li The callback function is called "in-line" - this means the function
* needs to return as fast as possible, as all other I/O will be suspended
* until the callback completes.
*
* Requires:
*
*\li 'manager' is a valid manager
*
*\li 'socketp' is a valid pointer, and *socketp == NULL
*
*\li 'fd' be opened.
*
* Ensures:
*
* '*socketp' is attached to the newly created fdwatch socket
*
* Returns:
*
*\li #ISC_R_SUCCESS
*\li #ISC_R_NOMEMORY
*\li #ISC_R_NORESOURCES
*\li #ISC_R_UNEXPECTED
*/
isc_result_t
isc_socket_create(isc_socketmgr_t *manager,
int pf,
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: types.h,v 1.37 2005/04/29 00:23:46 marka Exp $ */
/* $Id: types.h,v 1.38 2005/12/06 16:54:49 explorer Exp $ */
#ifndef ISC_TYPES_H
#define ISC_TYPES_H 1
......@@ -86,6 +86,7 @@ typedef struct isc_timer isc_timer_t; /*%< Timer */
typedef struct isc_timermgr isc_timermgr_t; /*%< Timer Manager */
typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *);
typedef int (*isc_sockfdwatch_t)(isc_task_t *, isc_socket_t *, void *);
/*% Resource */
typedef enum {
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: socket.c,v 1.257 2005/11/30 03:33:49 marka Exp $ */
/* $Id: socket.c,v 1.258 2005/12/06 16:54:49 explorer Exp $ */
/*! \file */
......@@ -186,6 +186,11 @@ struct isc_socket {
ISC_SOCKADDR_LEN_T recvcmsgbuflen;
char *sendcmsgbuf;
ISC_SOCKADDR_LEN_T sendcmsgbuflen;
void *fdwatcharg;
isc_sockfdwatch_t fdwatchcb;
int fdwatchflags;
isc_task_t *fdwatchtask;
};
#define SOCKET_MANAGER_MAGIC ISC_MAGIC('I', 'O', 'm', 'g')
......@@ -240,6 +245,8 @@ static void internal_accept(isc_task_t *, isc_event_t *);
static void internal_connect(isc_task_t *, isc_event_t *);
static void internal_recv(isc_task_t *, isc_event_t *);
static void internal_send(isc_task_t *, isc_event_t *);
static void internal_fdwatch_write(isc_task_t *, isc_event_t *);
static void internal_fdwatch_read(isc_task_t *, isc_event_t *);
static void process_cmsg(isc_socket_t *, struct msghdr *, isc_socketevent_t *);
static void build_msghdr_send(isc_socket_t *, isc_socketevent_t *,
struct msghdr *, struct iovec *, size_t *);
......@@ -1393,6 +1400,9 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
case isc_sockettype_unix:
sock->fd = socket(pf, SOCK_STREAM, 0);
break;
case isc_sockettype_fdwatch:
INSIST(type != isc_sockettype_fdwatch);
break;
}
#ifdef F_DUPFD
......@@ -1596,6 +1606,62 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
return (ISC_R_SUCCESS);
}
/*
* Create a new 'type' socket managed by 'manager'. Events
* will be posted to 'task' and when dispatched 'action' will be
* called with 'arg' as the arg value. The new socket is returned
* in 'socketp'.
*/
isc_result_t
isc_socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags,
isc_sockfdwatch_t callback, void *cbarg,
isc_task_t *task, isc_socket_t **socketp)
{
isc_socket_t *sock = NULL;
isc_result_t result;
REQUIRE(VALID_MANAGER(manager));
REQUIRE(socketp != NULL && *socketp == NULL);
result = allocate_socket(manager, isc_sockettype_fdwatch, &sock);
if (result != ISC_R_SUCCESS)
return (result);
sock->fd = fd;
sock->fdwatcharg = cbarg;
sock->fdwatchcb = callback;
sock->fdwatchflags = flags;
sock->fdwatchtask = task;
sock->references = 1;
*socketp = sock;
LOCK(&manager->lock);
/*
* Note we don't have to lock the socket like we normally would because
* there are no external references to it yet.
*/
manager->fds[sock->fd] = sock;
manager->fdstate[sock->fd] = MANAGED;
ISC_LIST_APPEND(manager->socklist, sock, link);
if (manager->maxfd < sock->fd)
manager->maxfd = sock->fd;
UNLOCK(&manager->lock);
if (flags & ISC_SOCKFDWATCH_READ)
select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
if (flags & ISC_SOCKFDWATCH_WRITE)
select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
ISC_MSG_CREATED, "fdwatch-created");
return (ISC_R_SUCCESS);
}
/*
* Attach to a socket. Caller must explicitly detach when it is done.
*/
......@@ -1649,25 +1715,37 @@ static void
dispatch_recv(isc_socket_t *sock) {
intev_t *iev;
isc_socketevent_t *ev;
isc_task_t *sender;
INSIST(!sock->pending_recv);
ev = ISC_LIST_HEAD(sock->recv_list);
if (ev == NULL)
return;
if (sock->type != isc_sockettype_fdwatch) {
ev = ISC_LIST_HEAD(sock->recv_list);
if (ev == NULL) {
socket_log(sock, NULL, EVENT, NULL, 0, 0,
"dispatch_recv: no pending reads");
return;
}
socket_log(sock, NULL, EVENT, NULL, 0, 0,
"dispatch_recv: event %p -> task %p",
ev, ev->ev_sender);
sender = ev->ev_sender;
} else {
sender = sock->fdwatchtask;
}
sock->pending_recv = 1;
iev = &sock->readable_ev;
socket_log(sock, NULL, EVENT, NULL, 0, 0,
"dispatch_recv: event %p -> task %p", ev, ev->ev_sender);
sock->references++;
iev->ev_sender = sock;
iev->ev_action = internal_recv;
if (sock->type == isc_sockettype_fdwatch)
iev->ev_action = internal_fdwatch_read;
else
iev->ev_action = internal_recv;
iev->ev_arg = sock;
isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
isc_task_send(sender, (isc_event_t **)&iev);
}
static void
......@@ -1689,7 +1767,10 @@ dispatch_send(isc_socket_t *sock) {
sock->references++;
iev->ev_sender = sock;
iev->ev_action = internal_send;
if (sock->type == isc_sockettype_fdwatch)
iev->ev_action = internal_fdwatch_write;
else
iev->ev_action = internal_send;
iev->ev_arg = sock;
isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
......@@ -2144,6 +2225,86 @@ internal_send(isc_task_t *me, isc_event_t *ev) {
UNLOCK(&sock->lock);
}
static void
internal_fdwatch_write(isc_task_t *me, isc_event_t *ev) {
isc_socket_t *sock;
int more_data;
INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
/*
* Find out what socket this is and lock it.
*/
sock = (isc_socket_t *)ev->ev_sender;
INSIST(VALID_SOCKET(sock));
LOCK(&sock->lock);
socket_log(sock, NULL, IOEVENT,
isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
"internal_fdwatch_write: task %p got event %p", me, ev);
INSIST(sock->pending_send == 1);
UNLOCK(&sock->lock);
more_data = (sock->fdwatchcb)(me, sock, sock->fdwatcharg);
LOCK(&sock->lock);
sock->pending_send = 0;
INSIST(sock->references > 0);
sock->references--; /* the internal event is done with this socket */
if (sock->references == 0) {
UNLOCK(&sock->lock);
destroy(&sock);
return;
}
if (more_data)
select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
UNLOCK(&sock->lock);
}
static void
internal_fdwatch_read(isc_task_t *me, isc_event_t *ev) {
isc_socket_t *sock;
int more_data;
INSIST(ev->ev_type == ISC_SOCKEVENT_INTR);
/*
* Find out what socket this is and lock it.
*/
sock = (isc_socket_t *)ev->ev_sender;
INSIST(VALID_SOCKET(sock));
LOCK(&sock->lock);
socket_log(sock, NULL, IOEVENT,
isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
"internal_fdwatch_read: task %p got event %p", me, ev);
INSIST(sock->pending_recv == 1);
UNLOCK(&sock->lock);
more_data = (sock->fdwatchcb)(me, sock, sock->fdwatcharg);
LOCK(&sock->lock);
sock->pending_recv = 0;
INSIST(sock->references > 0);
sock->references--; /* the internal event is done with this socket */
if (sock->references == 0) {
UNLOCK(&sock->lock);
destroy(&sock);
return;
}
if (more_data)
select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
UNLOCK(&sock->lock);
}
static void
process_fds(isc_socketmgr_t *manager, int maxfd,
fd_set *readfds, fd_set *writefds)
......@@ -2164,6 +2325,9 @@ process_fds(isc_socketmgr_t *manager, int maxfd,
continue;
#endif /* ISC_PLATFORM_USETHREADS */
/*
* If we need to close the socket, do it now.
*/
if (manager->fdstate[i] == CLOSE_PENDING) {
manager->fdstate[i] = CLOSED;
FD_CLR(i, &manager->read_fds);
......@@ -2173,6 +2337,8 @@ process_fds(isc_socketmgr_t *manager, int maxfd,
continue;
}
if (manager->fdstate[i] != MANAGED)
continue;
sock = manager->fds[i];
unlock_sock = ISC_FALSE;
......@@ -2279,8 +2445,9 @@ watcher(void *uap) {
isc_msgcat_get(isc_msgcat,
ISC_MSGSET_SOCKET,
ISC_MSG_WATCHERMSG,
"watcher got message %d"),
msg);
"watcher got message %d"
" for socket %d"),
msg, fd);
/*
* Nothing to read?
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment