/* * thread to combine salvager child logs * back into the main salvageserver log */ static void * SalvageLogCleanupThread(void * arg) { struct log_cleanup_node * cleanup; assert(pthread_mutex_lock(&worker_lock) == 0); while (1) { while (queue_IsEmpty(&log_cleanup_queue)) { assert(pthread_cond_wait(&log_cleanup_queue.queue_change_cv, &worker_lock) == 0); } while (queue_IsNotEmpty(&log_cleanup_queue)) { cleanup = queue_First(&log_cleanup_queue, log_cleanup_node); queue_Remove(cleanup); assert(pthread_mutex_unlock(&worker_lock) == 0); SalvageLogCleanup(cleanup->pid); free(cleanup); assert(pthread_mutex_lock(&worker_lock) == 0); } } assert(pthread_mutex_unlock(&worker_lock) == 0); return NULL; }
/* * thread to combine salvager child logs * back into the main salvageserver log */ static void * SalvageLogCleanupThread(void * arg) { struct log_cleanup_node * cleanup; MUTEX_ENTER(&worker_lock); while (1) { while (queue_IsEmpty(&log_cleanup_queue)) { CV_WAIT(&log_cleanup_queue.queue_change_cv, &worker_lock); } while (queue_IsNotEmpty(&log_cleanup_queue)) { cleanup = queue_First(&log_cleanup_queue, log_cleanup_node); queue_Remove(cleanup); MUTEX_EXIT(&worker_lock); SalvageLogCleanup(cleanup->pid); free(cleanup); MUTEX_ENTER(&worker_lock); } } MUTEX_EXIT(&worker_lock); return NULL; }
/** * dequeue a node from a list object. * * @param[in] list list object * @param[out] node_out address in which to store node object pointer * @param[in] state new node state * @param[in] block permit blocking on cv if asserted * * @return operation status * @retval 0 success * @retval EWOULDBLOCK block not asserted and nothing to dequeue * @retval EINTR blocking wait interrupted by list shutdown * * @post node object returned with node lock held and new state set * * @internal */ static int _afs_wq_node_list_dequeue(struct afs_work_queue_node_list * list, struct afs_work_queue_node ** node_out, afs_wq_work_state_t state, int block) { int ret = 0; struct afs_work_queue_node * node; MUTEX_ENTER(&list->lock); if (list->shutdown) { *node_out = NULL; ret = EINTR; goto done_sync; } if (!block && queue_IsEmpty(&list->list)) { *node_out = NULL; ret = EWOULDBLOCK; goto done_sync; } while (queue_IsEmpty(&list->list)) { if (list->shutdown) { *node_out = NULL; ret = EINTR; goto done_sync; } CV_WAIT(&list->cv, &list->lock); } *node_out = node = queue_First(&list->list, afs_work_queue_node); MUTEX_ENTER(&node->lock); queue_Remove(node); node->qidx = AFS_WQ_NODE_LIST_NONE; _afs_wq_node_state_change(node, state); done_sync: MUTEX_EXIT(&list->lock); return ret; }
/** * append to a node list object. * * @param[in] list list object * @param[in] node node object * @param[in] state new node state * * @return operation status * @retval 0 success * @retval AFS_WQ_ERROR raced to enqueue node * * @pre * - node lock held * - node is not on a list * - node is either not busy, or it is marked as busy by the calling thread * * @post * - enqueued on list * - node lock dropped * * @internal */ static int _afs_wq_node_list_enqueue(struct afs_work_queue_node_list * list, struct afs_work_queue_node * node, afs_wq_work_state_t state) { int code, ret = 0; if (node->qidx != AFS_WQ_NODE_LIST_NONE) { /* raced */ ret = AFS_WQ_ERROR; goto error; } /* deal with lock inversion */ code = MUTEX_TRYENTER(&list->lock); if (!code) { /* contended */ _afs_wq_node_state_change(node, AFS_WQ_NODE_STATE_BUSY); MUTEX_EXIT(&node->lock); MUTEX_ENTER(&list->lock); MUTEX_ENTER(&node->lock); /* assert state of the world (we set busy, so this should never happen) */ osi_Assert(queue_IsNotOnQueue(node)); } if (list->shutdown) { ret = AFS_WQ_ERROR; goto error_unlock; } osi_Assert(node->qidx == AFS_WQ_NODE_LIST_NONE); if (queue_IsEmpty(&list->list)) { /* wakeup a dequeue thread */ CV_SIGNAL(&list->cv); } queue_Append(&list->list, node); node->qidx = list->qidx; _afs_wq_node_state_change(node, state); error_unlock: MUTEX_EXIT(&node->lock); MUTEX_EXIT(&list->lock); error: return ret; }
/* Optimization for unmarshalling 32 bit integers */ int rx_ReadProc32(struct rx_call *call, afs_int32 * value) { int bytes; int tcurlen; int tnLeft; char *tcurpos; SPLVAR; /* Free any packets from the last call to ReadvProc/WritevProc */ if (!queue_IsEmpty(&call->iovq)) { #ifdef RXDEBUG_PACKET call->iovqc -= #endif /* RXDEBUG_PACKET */ rxi_FreePackets(0, &call->iovq); } /* * Most common case, all of the data is in the current iovec. * We are relying on nLeft being zero unless the call is in receive mode. */ tcurlen = call->curlen; tnLeft = call->nLeft; if (!call->error && tcurlen >= sizeof(afs_int32) && tnLeft >= sizeof(afs_int32)) { tcurpos = call->curpos; memcpy((char *)value, tcurpos, sizeof(afs_int32)); call->curpos = tcurpos + sizeof(afs_int32); call->curlen = (u_short)(tcurlen - sizeof(afs_int32)); call->nLeft = (u_short)(tnLeft - sizeof(afs_int32)); if (!call->nLeft && call->currentPacket != NULL) { /* out of packet. Get another one. */ rxi_FreePacket(call->currentPacket); call->currentPacket = (struct rx_packet *)0; } return sizeof(afs_int32); } NETPRI; bytes = rxi_ReadProc(call, (char *)value, sizeof(afs_int32)); USERPRI; return bytes; }
int rx_ReadProc(struct rx_call *call, char *buf, int nbytes) { int bytes; int tcurlen; int tnLeft; char *tcurpos; SPLVAR; /* Free any packets from the last call to ReadvProc/WritevProc */ if (!queue_IsEmpty(&call->iovq)) { #ifdef RXDEBUG_PACKET call->iovqc -= #endif /* RXDEBUG_PACKET */ rxi_FreePackets(0, &call->iovq); } /* * Most common case, all of the data is in the current iovec. * We are relying on nLeft being zero unless the call is in receive mode. */ tcurlen = call->curlen; tnLeft = call->nLeft; if (!call->error && tcurlen > nbytes && tnLeft > nbytes) { tcurpos = call->curpos; memcpy(buf, tcurpos, nbytes); call->curpos = tcurpos + nbytes; call->curlen = tcurlen - nbytes; call->nLeft = tnLeft - nbytes; if (!call->nLeft && call->currentPacket != NULL) { /* out of packet. Get another one. */ rxi_FreePacket(call->currentPacket); call->currentPacket = (struct rx_packet *)0; } return nbytes; } NETPRI; bytes = rxi_ReadProc(call, buf, nbytes); USERPRI; return bytes; }
/* Add the indicated event (function, arg) at the specified clock time */ struct rxevent * rxevent_Post(struct clock * when, void (*func)(), void *arg, void *arg1) /* when - When event should happen, in clock (clock.h) units */ { struct rxevent *ev, *qe, *qpr; #ifdef RXDEBUG if (Log) { struct clock now; clock_GetTime(&now); fprintf(Log, "%ld.%ld: rxevent_Post(%ld.%ld, %p, %p)\n", now.sec, now.usec, when->sec, when->usec, func, arg); } #endif #if defined(AFS_SGIMP_ENV) ASSERT(osi_rxislocked()); #endif /* * If we're short on free event entries, create a block of new ones and * add them to the free queue */ if (queue_IsEmpty(&rxevent_free)) { int i; #if defined(AFS_AIX32_ENV) && defined(KERNEL) ev = (struct rxevent *) rxi_Alloc(sizeof(struct rxevent)); queue_Append(&rxevent_free, &ev[0]), rxevent_nFree++; #else ev = (struct rxevent *) osi_Alloc(sizeof(struct rxevent) * rxevent_allocUnit); xsp = xfreemallocs; xfreemallocs = (struct xfreelist *) ev; xfreemallocs->next = xsp; for (i = 0; i < rxevent_allocUnit; i++) queue_Append(&rxevent_free, &ev[i]), rxevent_nFree++; #endif } /* Grab and initialize a new rxevent structure */ ev = queue_First(&rxevent_free, rxevent); queue_Remove(ev); rxevent_nFree--; /* Record user defined event state */ ev->eventTime = *when; ev->func = func; ev->arg = arg; ev->arg1 = arg1; rxevent_nPosted += 1; /* Rather than ++, to shut high-C up * regarding never-set variables */ /* * Locate a slot for the new entry. The queue is ordered by time, and we * assume that a new entry is likely to be greater than a majority of the * entries already on the queue (unless there's very few entries on the * queue), so we scan it backwards */ for (queue_ScanBackwards(&rxevent_queue, qe, qpr, rxevent)) { if (clock_Ge(when, &qe->eventTime)) { queue_InsertAfter(qe, ev); return ev; } } /* The event is to expire earlier than any existing events */ queue_Prepend(&rxevent_queue, ev); if (rxevent_ScheduledEarlierEvent) (*rxevent_ScheduledEarlierEvent) (); /* Notify our external * scheduler */ return ev; }
/* rxi_WritevProc -- internal version. * * Send buffers allocated in rxi_WritevAlloc. * * LOCKS USED -- called at netpri. */ int rxi_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes) { struct rx_packet *cp = NULL; #ifdef RX_TRACK_PACKETS struct rx_packet *p, *np; #endif int nextio; int requestCount; struct rx_queue tmpq; #ifdef RXDEBUG_PACKET u_short tmpqc; #endif requestCount = nbytes; nextio = 0; MUTEX_ENTER(&call->lock); if (call->error) { call->mode = RX_MODE_ERROR; } else if (call->mode != RX_MODE_SENDING) { call->error = RX_PROTOCOL_ERROR; } #ifdef AFS_GLOBAL_RXLOCK_KERNEL rxi_WaitforTQBusy(call); #endif /* AFS_GLOBAL_RXLOCK_KERNEL */ cp = call->currentPacket; if (call->error) { call->mode = RX_MODE_ERROR; MUTEX_EXIT(&call->lock); if (cp) { #ifdef RX_TRACK_PACKETS cp->flags &= ~RX_PKTFLAG_CP; cp->flags |= RX_PKTFLAG_IOVQ; #endif queue_Prepend(&call->iovq, cp); #ifdef RXDEBUG_PACKET call->iovqc++; #endif /* RXDEBUG_PACKET */ call->currentPacket = (struct rx_packet *)0; } #ifdef RXDEBUG_PACKET call->iovqc -= #endif /* RXDEBUG_PACKET */ rxi_FreePackets(0, &call->iovq); return 0; } /* Loop through the I/O vector adjusting packet pointers. * Place full packets back onto the iovq once they are ready * to send. Set RX_PROTOCOL_ERROR if any problems are found in * the iovec. We put the loop condition at the end to ensure that * a zero length write will push a short packet. */ nextio = 0; queue_Init(&tmpq); #ifdef RXDEBUG_PACKET tmpqc = 0; #endif /* RXDEBUG_PACKET */ do { if (call->nFree == 0 && cp) { clock_NewTime(); /* Bogus: need new time package */ /* The 0, below, specifies that it is not the last packet: * there will be others. PrepareSendPacket may * alter the packet length by up to * conn->securityMaxTrailerSize */ hadd32(call->bytesSent, cp->length); rxi_PrepareSendPacket(call, cp, 0); queue_Append(&tmpq, cp); #ifdef RXDEBUG_PACKET tmpqc++; #endif /* RXDEBUG_PACKET */ cp = call->currentPacket = (struct rx_packet *)0; /* The head of the iovq is now the current packet */ if (nbytes) { if (queue_IsEmpty(&call->iovq)) { MUTEX_EXIT(&call->lock); call->error = RX_PROTOCOL_ERROR; #ifdef RXDEBUG_PACKET tmpqc -= #endif /* RXDEBUG_PACKET */ rxi_FreePackets(0, &tmpq); return 0; } cp = queue_First(&call->iovq, rx_packet); queue_Remove(cp); #ifdef RX_TRACK_PACKETS cp->flags &= ~RX_PKTFLAG_IOVQ; #endif #ifdef RXDEBUG_PACKET call->iovqc--; #endif /* RXDEBUG_PACKET */ #ifdef RX_TRACK_PACKETS cp->flags |= RX_PKTFLAG_CP; #endif call->currentPacket = cp; call->nFree = cp->length; call->curvec = 1; call->curpos = (char *)cp->wirevec[1].iov_base + call->conn->securityHeaderSize; call->curlen = cp->wirevec[1].iov_len - call->conn->securityHeaderSize; } } if (nbytes) { /* The next iovec should point to the current position */ if (iov[nextio].iov_base != call->curpos || iov[nextio].iov_len > (int)call->curlen) { call->error = RX_PROTOCOL_ERROR; MUTEX_EXIT(&call->lock); if (cp) { #ifdef RX_TRACK_PACKETS cp->flags &= ~RX_PKTFLAG_CP; #endif queue_Prepend(&tmpq, cp); #ifdef RXDEBUG_PACKET tmpqc++; #endif /* RXDEBUG_PACKET */ cp = call->currentPacket = (struct rx_packet *)0; } #ifdef RXDEBUG_PACKET tmpqc -= #endif /* RXDEBUG_PACKET */ rxi_FreePackets(0, &tmpq); return 0; } nbytes -= iov[nextio].iov_len; call->curpos += iov[nextio].iov_len; call->curlen -= iov[nextio].iov_len; call->nFree -= iov[nextio].iov_len; nextio++; if (call->curlen == 0) { if (++call->curvec > cp->niovecs) { call->nFree = 0; } else { call->curpos = (char *)cp->wirevec[call->curvec].iov_base; call->curlen = cp->wirevec[call->curvec].iov_len; } } } } while (nbytes && nextio < nio); /* Move the packets from the temporary queue onto the transmit queue. * We may end up with more than call->twind packets on the queue. */ #ifdef RX_TRACK_PACKETS for (queue_Scan(&tmpq, p, np, rx_packet)) { p->flags |= RX_PKTFLAG_TQ; } #endif if (call->error) call->mode = RX_MODE_ERROR; queue_SpliceAppend(&call->tq, &tmpq); if (!(call->flags & (RX_CALL_FAST_RECOVER | RX_CALL_FAST_RECOVER_WAIT))) { rxi_Start(0, call, 0, 0); } /* Wait for the length of the transmit queue to fall below call->twind */ while (!call->error && call->tnext + 1 > call->tfirst + (2 * call->twind)) { clock_NewTime(); call->startWait = clock_Sec(); #ifdef RX_ENABLE_LOCKS CV_WAIT(&call->cv_twind, &call->lock); #else call->flags |= RX_CALL_WAIT_WINDOW_ALLOC; osi_rxSleep(&call->twind); #endif call->startWait = 0; } /* cp is no longer valid since we may have given up the lock */ cp = call->currentPacket; if (call->error) { call->mode = RX_MODE_ERROR; call->currentPacket = NULL; MUTEX_EXIT(&call->lock); if (cp) { #ifdef RX_TRACK_PACKETS cp->flags &= ~RX_PKTFLAG_CP; #endif rxi_FreePacket(cp); } return 0; } MUTEX_EXIT(&call->lock); return requestCount - nbytes; }