diff options
Diffstat (limited to 'debian/patches/pflocal.patch')
-rw-r--r-- | debian/patches/pflocal.patch | 675 |
1 files changed, 0 insertions, 675 deletions
diff --git a/debian/patches/pflocal.patch b/debian/patches/pflocal.patch deleted file mode 100644 index 7ebba8d5..00000000 --- a/debian/patches/pflocal.patch +++ /dev/null @@ -1,675 +0,0 @@ -2005-05-17 Neal H. Walfield <neal@gnu.org> - - * connq.h (struct connq_request): Remove forward. - (connq_listen): Wait for a request to be queued not until there is - a connection attempt. Remove REQ parameter. Update callers. - (connq_request_complete): Remove declaration. - (connq_connect): Wait for a slot to queue a request not until - there is an acceptor. Remove SOCK parameter. Update callers. - (connq_connect_complete): New declaration. - (connq_connect_cancel): New declaration. - - * connq.c (struct connq): Remove fields noqueue, queue, length, - head and tail. Add fields head, tail, count, max, connectors and - num_connectors. That is, replace the circular buffer with a - singly linked list. - (qnext): Remove function. - (struct connq_request): Remove field signal, lock, completed and - err. Add field next. - (connq_request_init): Rewrite according to new semantics. - (connq_request_enqueue): New function. - (connq_request_dequeue): New function. - (connq_create): Update according to new semantics. - (connq_destroy): Likewise. - (connq_listen): Rewrite to not block until there is a connector - but until there is a request in the queue. - (connq_request_complete): Remove function. - (connq_connect): Rewrite to not block until there is an acceptor - but until there is space for a request. - (connq_connect_complete): New function. - (connq_connect_cancel): New function. - (connq_compress): Remove dead code. - (connq_set_length): Rewrite. - - * socket.c (S_socket_connect): Create the server socket here... - (S_socket_accept): ... not here. - -merged upstream ---- - pflocal/connq.c | 341 +++++++++++++++++++++++++++++-------------------------- - pflocal/connq.h | 39 +++--- - pflocal/io.c | 8 - - pflocal/socket.c | 72 +++++------ - 4 files changed, 245 insertions(+), 215 deletions(-) - ---- a/pflocal/connq.c -+++ b/pflocal/connq.c -@@ -26,31 +26,22 @@ - /* A queue for queueing incoming connections. */ - struct connq - { -- /* True if all connection requests should be treated as non-blocking. */ -- int noqueue; -- - /* The connection request queue. */ -- struct connq_request **queue; -- unsigned length; -- /* Head is the position in QUEUE of the first request, and TAIL is the -- first free position in the queue. If HEAD == TAIL, then the queue is -- empty. Starting at HEAD, successive positions can be calculated by -- using qnext(). */ -- unsigned head, tail; -+ struct connq_request *head; -+ struct connq_request **tail; -+ unsigned count; -+ unsigned max; - - /* Threads that have done an accept on this queue wait on this condition. */ - struct condition listeners; - unsigned num_listeners; - -+ /* Threads that have done a connect on this queue wait on this condition. */ -+ struct condition connectors; -+ unsigned num_connectors; -+ - struct mutex lock; - }; -- --/* Returns the position CQ's queue after POS. */ --static inline unsigned --qnext (struct connq *cq, unsigned pos) --{ -- return (pos + 1 == cq->length) ? 0 : pos + 1; --} - - /* ---------------------------------------------------------------- */ - -@@ -58,30 +49,50 @@ qnext (struct connq *cq, unsigned pos) - get information from and to the thread. */ - struct connq_request - { -+ struct connq_request *next; -+ - /* The socket that's waiting to connect. */ - struct sock *sock; -- -- /* What the waiting thread blocks on. */ -- struct condition signal; -- struct mutex lock; -- -- /* Set to true when this request has been dealt with, to guard against -- spurious conditions being signaled. */ -- int completed; -- -- /* After the waiting thread is unblocked, this is the result, either 0 if -- SOCK has been connected, or an error. */ -- error_t err; - }; - - static inline void - connq_request_init (struct connq_request *req, struct sock *sock) - { -- req->err = 0; - req->sock = sock; -- req->completed = 0; -- condition_init (&req->signal); -- mutex_init (&req->lock); -+} -+ -+/* Enqueue connection request REQ onto CQ. CQ must be locked. */ -+static void -+connq_request_enqueue (struct connq *cq, struct connq_request *req) -+{ -+ assert (! mutex_try_lock (&cq->lock)); -+ -+ req->next = NULL; -+ *cq->tail = req; -+ cq->tail = &req->next; -+ -+ cq->count ++; -+} -+ -+/* Dequeue a pending request from CQ. CQ must be locked and must not -+ be empty. */ -+static struct connq_request * -+connq_request_dequeue (struct connq *cq) -+{ -+ struct connq_request *req; -+ -+ assert (! mutex_try_lock (&cq->lock)); -+ assert (cq->head); -+ -+ req = cq->head; -+ cq->head = req->next; -+ if (! cq->head) -+ /* We just dequeued the last element. Fixup the tail pointer. */ -+ cq->tail = &cq->head; -+ -+ cq->count --; -+ -+ return req; - } - - /* ---------------------------------------------------------------- */ -@@ -95,16 +106,20 @@ connq_create (struct connq **cq) - struct connq *new = malloc (sizeof (struct connq)); - - if (!new) -- return ENOMEM; -+ return ENOBUFS; -+ -+ new->head = NULL; -+ new->tail = &new->head; -+ new->count = 0; -+ /* By default, don't queue requests. */ -+ new->max = 0; - -- new->noqueue = 1; /* By default, don't queue requests. */ -- new->length = 0; -- new->head = new->tail = 0; -- new->queue = NULL; - new->num_listeners = 0; -+ new->num_connectors = 0; - - mutex_init (&new->lock); - condition_init (&new->listeners); -+ condition_init (&new->connectors); - - *cq = new; - return 0; -@@ -116,175 +131,189 @@ connq_destroy (struct connq *cq) - { - /* Everybody in the queue should hold a reference to the socket - containing the queue. */ -- assert (cq->length == 0); -- /* Nevertheless, malloc(0) or realloc(0) might allocate some small -- space. */ -- if (cq->queue) -- free (cq->queue); -+ assert (! cq->head); -+ assert (cq->count == 0); -+ - free (cq); - } - - /* ---------------------------------------------------------------- */ - --/* Wait for a connection attempt to be made on CQ, and return the connecting -- socket in SOCK, and a request tag in REQ. If REQ is NULL, the request is -- left in the queue, otherwise connq_request_complete must be called on REQ -- to allow the requesting thread to continue. If NOBLOCK is true, -- EWOULDBLOCK is returned when there are no immediate connections -- available. */ -+/* Return a connection request on CQ. If SOCK is NULL, the request is -+ left in the queue. If NOBLOCK is true, EWOULDBLOCK is returned -+ when there are no immediate connections available. */ - error_t --connq_listen (struct connq *cq, int noblock, -- struct connq_request **req, struct sock **sock) -+connq_listen (struct connq *cq, int noblock, struct sock **sock) - { -+ error_t err = 0; -+ - mutex_lock (&cq->lock); - -- if (noblock && cq->head == cq->tail) -+ if (noblock && cq->count == 0 && cq->num_connectors == 0) - { - mutex_unlock (&cq->lock); - return EWOULDBLOCK; - } - -+ if (! sock && (cq->count > 0 || cq->num_connectors > 0)) -+ /* The caller just wants to know if a connection ready. */ -+ { -+ mutex_unlock (&cq->lock); -+ return 0; -+ } -+ - cq->num_listeners++; - -- while (cq->head == cq->tail) -- if (hurd_condition_wait (&cq->listeners, &cq->lock)) -- { -- cq->num_listeners--; -- mutex_unlock (&cq->lock); -- return EINTR; -- } -+ if (cq->count == 0) -+ /* The request queue is empty. */ -+ { -+ assert (! cq->head); -+ -+ if (cq->num_connectors > 0) -+ /* Someone is waiting for an acceptor. Signal that we can -+ service their request. */ -+ condition_signal (&cq->connectors); -+ -+ do -+ if (hurd_condition_wait (&cq->listeners, &cq->lock)) -+ { -+ cq->num_listeners--; -+ err = EINTR; -+ goto out; -+ } -+ while (cq->count == 0); -+ } -+ -+ assert (cq->head); - -- if (req != NULL) -+ if (sock) - /* Dequeue the next request, if desired. */ - { -- *req = cq->queue[cq->head]; -- cq->head = qnext (cq, cq->head); -- if (sock != NULL) -- *sock = (*req)->sock; -+ struct connq_request *req = connq_request_dequeue (cq); -+ *sock = req->sock; -+ free (req); - } -+ else if (cq->num_listeners > 0) -+ /* The caller will not actually process this request but someone -+ else could. (This case is rare but possible: it would require -+ one thread to do a select on the socket and a second to do an -+ accept.) */ -+ condition_signal (&cq->listeners); -+ else -+ /* There is no one else to process the request and the connection -+ has now been initiated. This is not actually a problem as even -+ if the current queue limit is 0, the connector will queue the -+ request and another listener (should) eventually come along. -+ (In fact it is very probably as the caller has likely done a -+ select and will now follow up with an accept.) */ -+ ; - -- cq->num_listeners--; -- -+ out: - mutex_unlock (&cq->lock); -- -- return 0; --} -- --/* Return the error code ERR to the thread that made the listen request REQ, -- returned from a previous connq_listen. */ --void --connq_request_complete (struct connq_request *req, error_t err) --{ -- mutex_lock (&req->lock); -- req->err = err; -- req->completed = 1; -- condition_signal (&req->signal); -- mutex_unlock (&req->lock); -+ return err; - } - --/* Try to connect SOCK with the socket listening on CQ. If NOBLOCK is true, -- then return EWOULDBLOCK immediately when there are no immediate -- connections available. Neither SOCK nor CQ should be locked. */ -+/* Try to connect SOCK with the socket listening on CQ. If NOBLOCK is -+ true, then return EWOULDBLOCK if there are no connections -+ immediately available. On success, this call must be followed up -+ either connq_connect_complete or connq_connect_cancel. */ - error_t --connq_connect (struct connq *cq, int noblock, struct sock *sock) -+connq_connect (struct connq *cq, int noblock) - { -- error_t err = 0; -- unsigned next; -- - mutex_lock (&cq->lock); - - /* Check for listeners after we've locked CQ for good. */ -- if ((noblock || cq->noqueue) && cq->num_listeners == 0) -+ -+ if (noblock -+ && cq->count + cq->num_connectors >= cq->max + cq->num_listeners) -+ /* We are in non-blocking mode and would have to wait to secure an -+ entry in the listen queue. */ - { - mutex_unlock (&cq->lock); - return EWOULDBLOCK; - } - -- next = qnext (cq, cq->tail); -- if (next == cq->tail) -- /* The queue is full. */ -- err = ECONNREFUSED; -- else -- { -- struct connq_request req; -+ cq->num_connectors ++; -+ -+ while (cq->count + cq->num_connectors > cq->max + cq->num_listeners) -+ /* The queue is full and there is no immediate listener to service -+ us. Block until we can get a slot. */ -+ if (hurd_condition_wait (&cq->connectors, &cq->lock)) -+ { -+ cq->num_connectors --; -+ mutex_unlock (&cq->lock); -+ return EINTR; -+ } - -- connq_request_init (&req, sock); -+ mutex_unlock (&cq->lock); - -- cq->queue[cq->tail] = &req; -- cq->tail = next; -+ return 0; -+} - -- /* Hold REQ.LOCK before we signal the condition so that we're sure -- to be woken up. */ -- mutex_lock (&req.lock); -- condition_signal (&cq->listeners); -- mutex_unlock (&cq->lock); -+/* Follow up to connq_connect. Completes the connect, SOCK is the new -+ server socket. */ -+void -+connq_connect_complete (struct connq *cq, struct sock *sock) -+{ -+ struct connq_request *req; -+ -+ req = malloc (sizeof (struct connq_request)); -+ if (! req) -+ abort (); -+ -+ connq_request_init (req, sock); - -- while (!req.completed) -- condition_wait (&req.signal, &req.lock); -- err = req.err; -+ mutex_lock (&cq->lock); -+ -+ assert (cq->num_connectors > 0); -+ cq->num_connectors --; -+ -+ connq_request_enqueue (cq, req); - -- mutex_unlock (&req.lock); -+ if (cq->num_listeners > 0) -+ /* Wake a listener up. We must consume the listener ref here as -+ someone else might call this function before the listener -+ thread dequeues this request. */ -+ { -+ cq->num_listeners --; -+ condition_signal (&cq->listeners); - } - -- return err; -+ mutex_unlock (&cq->lock); - } -- --#if 0 --/* `Compresses' CQ, by removing any NULL entries. CQ should be locked. */ --static void --connq_compress (struct connq *cq) -+ -+/* Follow up to connq_connect. Cancel the connect. */ -+void -+connq_connect_cancel (struct connq *cq) - { -- unsigned pos; -- unsigned comp_tail = cq->head; -+ mutex_lock (&cq->lock); - -- /* Now compress the queue to remove any null entries we put in. */ -- for (pos = cq->head; pos != cq->tail; pos = qnext (cq, pos)) -- if (cq->queue[pos] != NULL) -- /* This position has a non-NULL request, so move it to the end of the -- compressed queue. */ -- { -- cq->queue[comp_tail] = cq->queue[pos]; -- comp_tail = qnext (cq, comp_tail); -- } -+ assert (cq->num_connectors > 0); -+ cq->num_connectors --; - -- /* Move back tail to only include what we kept in the queue. */ -- cq->tail = comp_tail; -+ if (cq->count + cq->num_connectors >= cq->max + cq->num_listeners) -+ /* A connector is blocked and could use the spot we reserved. */ -+ condition_signal (&cq->connectors); -+ -+ mutex_unlock (&cq->lock); - } --#endif - --/* Set CQ's queue length to LENGTH. Any sockets already waiting for a -- connections that are past the new length will fail with ECONNREFUSED. */ -+/* Set CQ's queue length to LENGTH. */ - error_t --connq_set_length (struct connq *cq, int length) -+connq_set_length (struct connq *cq, int max) - { -- mutex_lock (&cq->lock); -+ int omax; - -- if (length > cq->length) -- /* Growing the queue is simple... */ -- cq->queue = realloc (cq->queue, sizeof (struct connq_request *) * length); -- else -- /* Shrinking it less so. */ -- { -- int i; -- struct connq_request **new_queue = -- malloc (sizeof (struct connq_request *) * length); -- -- for (i = 0; i < cq->length && cq->head != cq->tail; i++) -- { -- if (i < length) -- /* Keep this connect request in the queue. */ -- new_queue[length - i] = cq->queue[cq->head]; -- else -- /* Punt this one. */ -- connq_request_complete (cq->queue[cq->head], ECONNREFUSED); -- cq->head = qnext (cq, cq->head); -- } -- -- free (cq->queue); -- cq->queue = new_queue; -- } -+ mutex_lock (&cq->lock); -+ omax = cq->max; -+ cq->max = max; - -- cq->noqueue = 0; /* Turn on queueing. */ -+ if (max > omax && cq->count >= omax && cq->count < max -+ && cq->num_connectors >= cq->num_listeners) -+ /* This is an increase in the number of connection slots which has -+ made some slots available and there are waiting threads. Wake -+ them up. */ -+ condition_broadcast (&cq->listeners); - - mutex_unlock (&cq->lock); - ---- a/pflocal/connq.h -+++ b/pflocal/connq.h -@@ -23,9 +23,8 @@ - - #include <errno.h> - --/* Unknown types */ -+/* Forward. */ - struct connq; --struct connq_request; - struct sock; - - /* Create a new listening queue, returning it in CQ. The resulting queue -@@ -36,26 +35,26 @@ error_t connq_create (struct connq **cq) - /* Destroy a queue. */ - void connq_destroy (struct connq *cq); - --/* Wait for a connection attempt to be made on CQ, and return the connecting -- socket in SOCK, and a request tag in REQ. If REQ is NULL, the request is -- left in the queue, otherwise connq_request_complete must be called on REQ -- to allow the requesting thread to continue. If NOBLOCK is true, -- EWOULDBLOCK is returned when there are no immediate connections -- available. CQ should be unlocked. */ --error_t connq_listen (struct connq *cq, int noblock, -- struct connq_request **req, struct sock **sock); -- --/* Return the error code ERR to the thread that made the listen request REQ, -- returned from a previous connq_listen. */ --void connq_request_complete (struct connq_request *req, error_t err); -+/* Return a connection request on CQ. If SOCK is NULL, the request is -+ left in the queue. If NOBLOCK is true, EWOULDBLOCK is returned -+ when there are no immediate connections available. */ -+error_t connq_listen (struct connq *cq, int noblock, struct sock **sock); -+ -+/* Try to connect SOCK with the socket listening on CQ. If NOBLOCK is -+ true, then return EWOULDBLOCK if there are no connections -+ immediately available. On success, this call must be followed up -+ either connq_connect_complete or connq_connect_cancel. */ -+error_t connq_connect (struct connq *cq, int noblock); -+ -+/* Follow up to connq_connect. Completes the connection, SOCK is the -+ new server socket. */ -+void connq_connect_complete (struct connq *cq, struct sock *sock); -+ -+/* Follow up to connq_connect. Cancel the connect. */ -+void connq_connect_cancel (struct connq *cq); - - /* Set CQ's queue length to LENGTH. Any sockets already waiting for a -- connections that are past the new length will fail with ECONNREFUSED. */ -+ connections that are past the new length remain. */ - error_t connq_set_length (struct connq *cq, int length); - --/* Try to connect SOCK with the socket listening on CQ. If NOBLOCK is true, -- then return EWOULDBLOCK immediately when there are no immediate -- connections available. Neither SOCK nor CQ should be locked. */ --error_t connq_connect (struct connq *cq, int noblock, struct sock *sock); -- - #endif /* __CONNQ_H__ */ ---- a/pflocal/io.c -+++ b/pflocal/io.c -@@ -199,16 +199,16 @@ S_io_select (struct sock_user *user, - - if (*select_type & SELECT_READ) - { -- /* Wait for a connect. Passing in NULL for REQ means that the -- request won't be dequeued. */ -- if (connq_listen (sock->listen_queue, 1, NULL, NULL) == 0) -+ /* Wait for a connect. Passing in NULL for SOCK means that -+ the request won't be dequeued. */ -+ if (connq_listen (sock->listen_queue, 1, NULL) == 0) - /* We can satisfy this request immediately. */ - return 0; - else - /* Gotta wait... */ - { - ports_interrupt_self_on_port_death (user, reply); -- return connq_listen (sock->listen_queue, 0, NULL, NULL); -+ return connq_listen (sock->listen_queue, 0, NULL); - } - } - } ---- a/pflocal/socket.c -+++ b/pflocal/socket.c -@@ -110,7 +110,7 @@ S_socket_connect (struct sock_user *user - else if (sock->flags & SOCK_CONNECTED) - /* SOCK_CONNECTED is only set for connection-oriented sockets, - which can only ever connect once. [If we didn't do this test -- here, it would eventually fail when it the listening socket -+ here, it would eventually fail when the listening socket - tried to accept our connection request.] */ - err = EISCONN; - else -@@ -118,16 +118,35 @@ S_socket_connect (struct sock_user *user - /* Assert that we're trying to connect, so anyone else trying - to do so will fail with EALREADY. */ - sock->connect_queue = cq; -- mutex_unlock (&sock->lock); /* Unlock SOCK while waiting. */ -+ /* Unlock SOCK while waiting. */ -+ mutex_unlock (&sock->lock); - -- /* Try to connect. */ -- err = connq_connect (cq, sock->flags & SOCK_NONBLOCK, sock); -+ err = connq_connect (peer->listen_queue, -+ sock->flags & SOCK_NONBLOCK); -+ if (!err) -+ { -+ struct sock *server; -+ -+ err = sock_clone (peer, &server); -+ if (!err) -+ { -+ err = sock_connect (sock, server); -+ if (!err) -+ connq_connect_complete (peer->listen_queue, server); -+ else -+ sock_free (server); -+ } - -- /* We can safely set CONNECT_QUEUE to NULL, as no one else can -+ mutex_lock (&sock->lock); -+ if (err) -+ connq_connect_cancel (peer->listen_queue); -+ } -+ -+ /* We must set CONNECT_QUEUE to NULL, as no one else can - set it until we've done so. */ -- mutex_lock (&sock->lock); - sock->connect_queue = NULL; - } -+ - mutex_unlock (&sock->lock); - } - else -@@ -157,42 +176,25 @@ S_socket_accept (struct sock_user *user, - err = ensure_connq (sock); - if (!err) - { -- struct connq_request *req; - struct sock *peer_sock; - -- err = -- connq_listen (sock->listen_queue, sock->flags & SOCK_NONBLOCK, -- &req, &peer_sock); -+ err = connq_listen (sock->listen_queue, sock->flags & SOCK_NONBLOCK, -+ &peer_sock); - if (!err) - { -- struct sock *conn_sock; -- -- err = sock_clone (sock, &conn_sock); -+ struct addr *peer_addr; -+ *port_type = MACH_MSG_TYPE_MAKE_SEND; -+ err = sock_create_port (peer_sock, port); -+ if (!err) -+ err = sock_get_addr (peer_sock, &peer_addr); - if (!err) - { -- err = sock_connect (conn_sock, peer_sock); -- if (!err) -- { -- struct addr *peer_addr; -- *port_type = MACH_MSG_TYPE_MAKE_SEND; -- err = sock_create_port (conn_sock, port); -- if (!err) -- err = sock_get_addr (peer_sock, &peer_addr); -- if (!err) -- { -- *peer_addr_port = ports_get_right (peer_addr); -- *peer_addr_port_type = MACH_MSG_TYPE_MAKE_SEND; -- ports_port_deref (peer_addr); -- } -- else -- /* TEAR DOWN THE CONNECTION XXX */; -- } -- if (err) -- sock_free (conn_sock); -+ *peer_addr_port = ports_get_right (peer_addr); -+ *peer_addr_port_type = MACH_MSG_TYPE_MAKE_SEND; -+ ports_port_deref (peer_addr); - } -- -- /* Communicate any error (or success) to the connecting thread. */ -- connq_request_complete (req, err); -+ else -+ /* TEAR DOWN THE CONNECTION XXX */; - } - } - |