This commit is contained in:
Michael Graff 1998-11-10 01:56:44 +00:00
parent 91c21a94b8
commit bb039bc91e
3 changed files with 237 additions and 68 deletions

View file

@ -37,8 +37,6 @@ my_shutdown(isc_task_t task, isc_event_t event)
fflush(stdout);
isc_event_free(&event);
tasks_done++;
return (ISC_TRUE);
}
@ -51,6 +49,8 @@ my_listen(isc_task_t task, isc_event_t event)
fflush(stdout);
isc_event_free(&event);
tasks_done++;
return (ISC_TRUE);
}
@ -138,11 +138,6 @@ main(int argc, char *argv[])
sizeof *event);
isc_task_send(t2, &event);
isc_task_shutdown(t1);
isc_task_shutdown(t2);
isc_task_detach(&t1);
isc_task_detach(&t2);
/*
* Grr! there is no way to say "wake me when it's over"
*/
@ -151,6 +146,11 @@ main(int argc, char *argv[])
sleep(2);
}
isc_task_shutdown(t1);
isc_task_shutdown(t2);
isc_task_detach(&t1);
isc_task_detach(&t2);
printf("destroy\n");
isc_socket_detach(&so1);
isc_socket_detach(&so2);

View file

@ -1,4 +1,4 @@
/* $Id: socket.h,v 1.2 1998/11/06 01:45:35 explorer Exp $ */
/* $Id: socket.h,v 1.3 1998/11/10 01:56:44 explorer Exp $ */
#ifndef ISC_SOCKET_H
#define ISC_SOCKET_H 1
@ -82,6 +82,11 @@ typedef struct isc_socketevent {
int addrlength; /* length of address */
} *isc_socketevent_t;
typedef struct isc_socket_newconev {
struct isc_event common;
isc_socket_t newsocket;
} *isc_socket_newconnev_t;
#define ISC_SOCKEVENT_ANYEVENT (0)
#define ISC_SOCKEVENT_RECVDONE (ISC_EVENTCLASS_SOCKET + 1)
#define ISC_SOCKEVENT_SENDDONE (ISC_EVENTCLASS_SOCKET + 2)

View file

@ -1,4 +1,4 @@
/* $Id: socket.c,v 1.3 1998/11/07 02:31:04 explorer Exp $ */
/* $Id: socket.c,v 1.4 1998/11/10 01:56:43 explorer Exp $ */
#include "attribute.h"
@ -40,9 +40,9 @@
* Debugging
*/
#if 1
#define XTRACE(a) fprintf(stderr, a)
#define XENTER(a) fprintf(stderr, "ENTER %s\n", (a))
#define XEXIT(a) fprintf(stderr, "EXIT %s\n", (a))
#define XTRACE(a) printf a
#define XENTER(a) printf("ENTER %s\n", (a))
#define XEXIT(a) printf("EXIT %s\n", (a))
#else
#define XTRACE(a)
#define XENTER(a)
@ -58,12 +58,20 @@ typedef struct isc_socket_intev {
isc_task_t task; /* task to send these to */
isc_socketevent_t done_ev; /* the done event to post */
isc_boolean_t partial; /* partial i/o ok */
isc_boolean_t listener;
isc_boolean_t canceled; /* I/O was canceled */
isc_taskaction_t action; /* listen needs this too */
void *arg; /* listen needs this too */
LINK(struct isc_socket_intev) link;
} *isc_socket_intev_t;
typedef struct isc_socket_ncintev {
struct isc_event common;
isc_boolean_t canceled;
isc_task_t task;
isc_socket_newconnev_t done; /* the done event */
isc_socket_t sock; /* the socket we will pass or destroy */
} *isc_socket_ncintev_t;
#define SOCKET_MAGIC 0x494f696fU /* IOio */
#define VALID_SOCKET(t) ((t) != NULL && \
(t)->magic == SOCKET_MAGIC)
@ -79,6 +87,7 @@ struct isc_socket {
LIST(struct isc_socket_intev) write_list;
isc_boolean_t pending_read;
isc_boolean_t pending_write;
isc_boolean_t listener; /* listener socket */
isc_sockettype_t type;
isc_socket_intev_t riev;
isc_socket_intev_t wiev;
@ -106,42 +115,45 @@ struct isc_socketmgr {
sig_atomic_t pipe_msgs;
};
typedef int select_msg_t;
#define SELECT_POKE_SHUTDOWN (-1)
#define SELECT_POKE_NOTHING (-2)
static void send_done_event(isc_socket_t, isc_socket_intev_t *,
isc_socketevent_t *, isc_result_t);
static void done_event_destroy(isc_event_t);
static void free_socket(isc_socket_t *);
static isc_result_t allocate_socket(isc_socketmgr_t, isc_sockettype_t,
isc_socket_t *);
/*
* poke the select loop when there is something for us to do. Manager must
* be locked.
*/
static void
select_poke(isc_socketmgr_t mgr, select_msg_t msg)
select_poke(isc_socketmgr_t mgr, int msg)
{
int cc;
cc = write(mgr->pipe_fds[1], &msg, sizeof(select_msg_t));
XTRACE(("Poking watcher with data %d\n", msg));
cc = write(mgr->pipe_fds[1], &msg, sizeof(int));
if (cc < 0)
UNEXPECTED_ERROR(__FILE__, __LINE__,
"write() failed during watcher poke: %s",
strerror(errno));
INSIST(cc == sizeof(select_msg_t));
INSIST(cc == sizeof(int));
}
/*
* read a message on the internal fd.
*/
static select_msg_t
static int
select_readmsg(isc_socketmgr_t mgr)
{
select_msg_t msg;
int msg;
int cc;
cc = read(mgr->pipe_fds[0], &msg, sizeof(select_msg_t));
cc = read(mgr->pipe_fds[0], &msg, sizeof(int));
if (cc < 0) {
if (errno == EWOULDBLOCK)
return SELECT_POKE_NOTHING;
@ -152,7 +164,7 @@ select_readmsg(isc_socketmgr_t mgr)
return SELECT_POKE_NOTHING; /* XXX */
}
INSIST(cc == sizeof(select_msg_t));
INSIST(cc == sizeof(int));
return msg;
}
@ -211,21 +223,87 @@ destroy(isc_socket_t sock)
/*
* Noone has this socket open, so the watcher doesn't have to be
* poked.
* poked, and the socket doesn't have to be locked.
*/
manager->fds[sock->fd] = NULL;
manager->nsockets--;
UNLOCK(&manager->lock);
if (sock->riev)
isc_event_free((isc_event_t *)&sock->riev);
if (sock->wiev)
isc_event_free((isc_event_t *)&sock->wiev);
free_socket(&sock);
}
static isc_result_t
allocate_socket(isc_socketmgr_t manager, isc_sockettype_t type,
isc_socket_t *socketp)
{
isc_socket_t sock;
sock = isc_mem_get(manager->mctx, sizeof *sock);
if (sock == NULL)
return (NULL);
sock->magic = SOCKET_MAGIC;
sock->references = 1;
sock->manager = manager;
sock->type = type;
/*
* set up list of readers and writers to be initially empty
*/
INIT_LIST(sock->read_list);
INIT_LIST(sock->write_list);
sock->pending_read = ISC_FALSE;
sock->pending_write = ISC_FALSE;
/*
* initialize the lock
*/
if (isc_mutex_init(&sock->lock) != ISC_R_SUCCESS) {
sock->magic = 0;
isc_mem_put(manager->mctx, sock, sizeof *sock);
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_mutex_init() failed");
return (ISC_R_UNEXPECTED);
}
*socketp = sock;
return (ISC_R_SUCCESS);
}
/*
* This event requires that the various lists be empty, that the reference
* count be 1, and that the magic number is valid. The other socket bits,
* like the lock, must be initialized as well. The fd associated must be
* marked as closed, by setting it to -1 on close, or this routine will
* also close the socket.
*/
static void
free_socket(isc_socket_t *socketp)
{
isc_socket_t sock = *socketp;
REQUIRE(sock->references == 1);
REQUIRE(VALID_SOCKET(sock));
REQUIRE(!sock->listener);
REQUIRE(!sock->pending_read);
REQUIRE(!sock->pending_write);
REQUIRE(EMPTY(sock->read_list));
REQUIRE(EMPTY(sock->write_list));
sock->magic = 0;
if (sock->fd == -1) {
close(sock->fd);
sock->fd = -1;
}
(void)isc_mutex_destroy(&sock->lock);
sock->magic = 0;
isc_mem_put(manager->mctx, sock, sizeof *sock);
isc_mem_put(sock->manager->mctx, sock, sizeof *sock);
}
/*
@ -239,29 +317,18 @@ isc_result_t
isc_socket_create(isc_socketmgr_t manager, isc_sockettype_t type,
isc_socket_t *socketp)
{
isc_socket_t sock;
isc_socket_t sock = NULL;
isc_result_t ret;
REQUIRE(VALID_MANAGER(manager));
REQUIRE(socketp != NULL && *socketp == NULL);
XENTER("isc_socket_create");
sock = isc_mem_get(manager->mctx, sizeof *sock);
if (sock == NULL)
return (ISC_R_NOMEMORY);
sock->magic = SOCKET_MAGIC;
sock->manager = manager;
sock->references = 1;
sock->type = type;
/*
* set up list of readers and writers to be initially empty
*/
INIT_LIST(sock->read_list);
INIT_LIST(sock->write_list);
sock->pending_read = ISC_FALSE;
sock->pending_write = ISC_FALSE;
ret = allocate_socket(manager, type, &sock);
if (ret != ISC_R_SUCCESS)
return (ret);
/*
* Create the associated socket XXX
@ -275,7 +342,7 @@ isc_socket_create(isc_socketmgr_t manager, isc_sockettype_t type,
break;
}
if (sock->fd < 0) {
isc_mem_put(manager->mctx, sock, sizeof *sock);
free_socket(&sock);
switch (errno) {
case EMFILE:
@ -293,24 +360,12 @@ isc_socket_create(isc_socketmgr_t manager, isc_sockettype_t type,
}
if (make_nonblock(sock->fd) != ISC_R_SUCCESS) {
isc_mem_put(manager->mctx, sock, sizeof *sock);
close(sock->fd);
free_socket(&sock);
UNEXPECTED_ERROR(__FILE__, __LINE__,
"make_nonblock(%d)", sock->fd);
return (ISC_R_UNEXPECTED);
}
/*
* initialize the lock
*/
if (isc_mutex_init(&sock->lock) != ISC_R_SUCCESS) {
isc_mem_put(manager->mctx, sock, sizeof *sock);
close(sock->fd);
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_mutex_init() failed");
return (ISC_R_UNEXPECTED);
}
LOCK(&manager->lock);
/*
@ -440,9 +495,76 @@ send_done_event(isc_socket_t sock, isc_socket_intev_t *iev,
isc_event_free((isc_event_t *)iev);
}
/*
* Call accept() on a socket, to get the new file descriptor. The listen
* socket is used as a prototype to create a new isc_socket_t. The new
* socket is referenced twice (one for the task which is receiving this
* message, and once for the message itself) so the task does not need to
* attach to the socket again. The task is not attached at all.
*/
static isc_boolean_t
internal_accept(isc_task_t task, isc_event_t ev)
{
isc_socket_t sock;
isc_socket_t nsock = NULL;
isc_socket_newconnev_t dev;
isc_socket_ncintev_t iev;
struct sockaddr addr;
int addrlen;
int fd;
sock = ev->sender;
iev = (isc_socket_ncintev_t)ev;
LOCK(&sock->lock);
XTRACE(("internal_accept called, locked sock %p\n", sock));
REQUIRE(sock->pending_read);
REQUIRE(sock->listener);
REQUIRE(!EMPTY(sock->read_list));
REQUIRE(iev->task == task);
sock->pending_read = ISC_FALSE;
/*
* Try to accept the new connection. If the accept fails with
* EWOULDBLOCK, simply poke the watcher to watch this socket
* again.
*/
fd = accept(sock->fd, &addr, &addrlen);
if (fd < 0) {
if (errno == EWOULDBLOCK) {
sock->pending_read = ISC_FALSE;
select_poke(sock->manager, sock->fd);
UNLOCK(&sock->lock);
return (0);
}
/*
* If some other error, ignore it as well and hope
* for the best, but log it. XXX This will have to be
* changed, thanks to broken OSs trying to overload what
* accept does.
*/
sock->pending_read = ISC_FALSE;
select_poke(sock->manager, sock->fd);
UNLOCK(&sock->lock);
return (0);
}
/*
* The accept succeeded. Pull off the done event and set the
* fd and other information in the socket descriptor here. These
* were preallocated for us.
*/
dev = iev->done;
nsock = iev->sock;
nsock->fd = fd;
dev->newsocket = nsock;
return (0);
}
static isc_boolean_t
@ -596,7 +718,7 @@ watcher(void *uap)
int cc;
fd_set readfds;
fd_set writefds;
select_msg_t msg;
int msg;
isc_boolean_t unlock_sock;
int i;
isc_socket_intev_t iev;
@ -627,6 +749,8 @@ watcher(void *uap)
LOCK(&manager->lock);
XTRACE(("watcher got manager lock\n"));
/*
* Process reads on internal, control fd.
*/
@ -634,6 +758,8 @@ watcher(void *uap)
while (1) {
msg = select_readmsg(manager);
XTRACE(("watcher got message %d\n", msg));
/*
* Nothing to read?
*/
@ -660,6 +786,8 @@ watcher(void *uap)
sock = manager->fds[msg];
LOCK(&sock->lock);
XTRACE(("watcher locked socket %p\n",
sock));
/*
* If there are no events, or there
@ -669,20 +797,26 @@ watcher(void *uap)
* Otherwise, set it.
*/
iev = HEAD(sock->read_list);
if (iev == NULL || sock->pending_read)
if (iev == NULL || sock->pending_read) {
FD_CLR(sock->fd,
&manager->read_fds);
else
XTRACE(("watch cleared r\n"));
} else {
FD_SET(sock->fd,
&manager->read_fds);
XTRACE(("watch set r\n"));
}
iev = HEAD(sock->write_list);
if (iev == NULL || sock->pending_write)
if (iev == NULL || sock->pending_write) {
FD_CLR(sock->fd,
&manager->write_fds);
else
XTRACE(("watch cleared w\n"));
} else {
FD_SET(sock->fd,
&manager->write_fds);
XTRACE(("watch set w\n"));
}
UNLOCK(&sock->lock);
}
@ -698,12 +832,16 @@ watcher(void *uap)
sock = manager->fds[i];
unlock_sock = ISC_FALSE;
if (FD_ISSET(i, &readfds)) {
XTRACE(("watcher r on %d, sock %p\n",
i, manager->fds[i]));
unlock_sock = ISC_TRUE;
LOCK(&sock->lock);
dispatch_read(sock);
FD_CLR(i, &manager->read_fds);
}
if (FD_ISSET(i, &writefds)) {
XTRACE(("watcher w on %d, sock %p\n",
i, manager->fds[i]));
if (!unlock_sock) {
unlock_sock = ISC_TRUE;
LOCK(&sock->lock);
@ -976,7 +1114,7 @@ isc_socket_listen(isc_socket_t sock, int backlog, isc_task_t task,
isc_taskaction_t action, void *arg)
{
isc_socket_intev_t iev;
isc_task_t ntask;
isc_task_t ntask = NULL;
isc_socketmgr_t manager;
manager = sock->manager;
@ -994,9 +1132,25 @@ isc_socket_listen(isc_socket_t sock, int backlog, isc_task_t task,
LOCK(&sock->lock);
if (listen(sock->fd, backlog) < 0) {
isc_event_free((isc_event_t *)&iev);
if (sock->type != isc_socket_tcp) {
UNLOCK(&sock->lock);
isc_event_free((isc_event_t *)&iev);
UNEXPECTED_ERROR(__FILE__, __LINE__,
"Socket is not isc_socket_tcp");
return (ISC_R_UNEXPECTED);
}
if (sock->listener) {
UNLOCK(&sock->lock);
isc_event_free((isc_event_t *)&iev);
UNEXPECTED_ERROR(__FILE__, __LINE__,
"Socket already listener");
return (ISC_R_UNEXPECTED);
}
if (listen(sock->fd, backlog) < 0) {
UNLOCK(&sock->lock);
isc_event_free((isc_event_t *)&iev);
UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s",
strerror(errno));
@ -1008,14 +1162,24 @@ isc_socket_listen(isc_socket_t sock, int backlog, isc_task_t task,
*/
isc_task_attach(task, &ntask);
sock->references++;
sock->listener = ISC_TRUE;
iev->task = ntask;
iev->done_ev = NULL;
iev->partial = ISC_FALSE; /* state doesn't really matter */
iev->listener = ISC_TRUE;
iev->action = action;
iev->arg = arg;
/*
* poke watcher here. We still have the socket locked, so there
* is no race condition. We will keep the lock for such a short
* bit of time waking it up now or later won't matter all that much.
*/
if (EMPTY(sock->read_list))
select_poke(manager, sock->fd);
ENQUEUE(sock->read_list, iev, link);
UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);