2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 06:25:31 +00:00

add file descriptor watching functions, Unix only.

This commit is contained in:
Michael Graff
2005-12-06 16:54:49 +00:00
parent 309a3b5808
commit e6c3041c28
3 changed files with 231 additions and 15 deletions

View File

@@ -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?