static bool recalc_brl_timeout(void) { struct blocking_lock_record *blr; struct timeval next_timeout; TALLOC_FREE(brl_timeout); next_timeout = timeval_zero(); for (blr = blocking_lock_queue; blr; blr = blr->next) { if (timeval_is_zero(&blr->expire_time)) { /* * If we're blocked on pid 0xFFFFFFFF this is * a POSIX lock, so calculate a timeout of * 10 seconds into the future. */ if (blr->blocking_pid == 0xFFFFFFFF) { struct timeval psx_to = timeval_current_ofs(10, 0); next_timeout = timeval_min(&next_timeout, &psx_to); } continue; } if (timeval_is_zero(&next_timeout)) { next_timeout = blr->expire_time; } else { next_timeout = timeval_min(&next_timeout, &blr->expire_time); } } if (timeval_is_zero(&next_timeout)) { DEBUG(10, ("Next timeout = Infinite.\n")); return True; } if (DEBUGLVL(10)) { struct timeval cur, from_now; cur = timeval_current(); from_now = timeval_until(&cur, &next_timeout); DEBUG(10, ("Next timeout = %d.%d seconds from now.\n", (int)from_now.tv_sec, (int)from_now.tv_usec)); } if (!(brl_timeout = event_add_timed(smbd_event_context(), NULL, next_timeout, brl_timeout_fn, NULL))) { return False; } return True; }
struct timeval *get_timed_events_timeout(struct timeval *to_ret) { struct timeval now; if (timed_events == NULL) { return NULL; } now = timeval_current(); *to_ret = timeval_until(&now, &timed_events->when); DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec, (int)to_ret->tv_usec)); return to_ret; }
static bool recalc_brl_timeout(struct smbd_server_connection *sconn) { struct blocking_lock_record *blr; struct timeval next_timeout; int max_brl_timeout = lp_parm_int(-1, "brl", "recalctime", 5); TALLOC_FREE(sconn->smb1.locks.brl_timeout); next_timeout = timeval_zero(); for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = blr->next) { if (timeval_is_zero(&blr->expire_time)) { /* * If we're blocked on pid 0xFFFFFFFFFFFFFFFFLL this is * a POSIX lock, so calculate a timeout of * 10 seconds into the future. */ if (blr->blocking_smblctx == 0xFFFFFFFFFFFFFFFFLL) { struct timeval psx_to = timeval_current_ofs(10, 0); next_timeout = timeval_brl_min(&next_timeout, &psx_to); } continue; } next_timeout = timeval_brl_min(&next_timeout, &blr->expire_time); } if (timeval_is_zero(&next_timeout)) { DEBUG(10, ("Next timeout = Infinite.\n")); return True; } /* to account for unclean shutdowns by clients we need a maximum timeout that we use for checking pending locks. If we have any pending locks at all, then check if the pending lock can continue at least every brl:recalctime seconds (default 5 seconds). This saves us needing to do a message_send_all() in the SIGCHLD handler in the parent daemon. That message_send_all() caused O(n^2) work to be done when IP failovers happened in clustered Samba, which could make the entire system unusable for many minutes. */ if (max_brl_timeout > 0) { struct timeval min_to = timeval_current_ofs(max_brl_timeout, 0); next_timeout = timeval_min(&next_timeout, &min_to); } if (DEBUGLVL(10)) { struct timeval cur, from_now; cur = timeval_current(); from_now = timeval_until(&cur, &next_timeout); DEBUG(10, ("Next timeout = %d.%d seconds from now.\n", (int)from_now.tv_sec, (int)from_now.tv_usec)); } sconn->smb1.locks.brl_timeout = tevent_add_timer(sconn->ev_ctx, NULL, next_timeout, brl_timeout_fn, sconn); if (sconn->smb1.locks.brl_timeout == NULL) { return False; } return True; }
/* test the TestSleep interface */ static bool test_sleep(struct torture_context *tctx, struct dcerpc_pipe *p) { int i; NTSTATUS status; #define ASYNC_COUNT 3 struct rpc_request *req[ASYNC_COUNT]; struct echo_TestSleep r[ASYNC_COUNT]; bool done[ASYNC_COUNT]; struct timeval snd[ASYNC_COUNT]; struct timeval rcv[ASYNC_COUNT]; struct timeval diff[ASYNC_COUNT]; struct tevent_context *ctx; int total_done = 0; if (torture_setting_bool(tctx, "quick", false)) { torture_skip(tctx, "TestSleep disabled - use \"torture:quick=no\" to enable\n"); } torture_comment(tctx, "Testing TestSleep - use \"torture:quick=yes\" to disable\n"); for (i=0;i<ASYNC_COUNT;i++) { done[i] = false; snd[i] = timeval_current(); rcv[i] = timeval_zero(); r[i].in.seconds = ASYNC_COUNT-i; req[i] = dcerpc_echo_TestSleep_send(p, tctx, &r[i]); torture_assert(tctx, req[i], "Failed to send async sleep request\n"); } ctx = dcerpc_event_context(p); while (total_done < ASYNC_COUNT) { torture_assert(tctx, event_loop_once(ctx) == 0, "Event context loop failed"); for (i=0;i<ASYNC_COUNT;i++) { if (done[i] == false && req[i]->state == RPC_REQUEST_DONE) { int rounded_tdiff; total_done++; done[i] = true; rcv[i] = timeval_current(); diff[i] = timeval_until(&snd[i], &rcv[i]); rounded_tdiff = (int)(0.5 + diff[i].tv_sec + (1.0e-6*diff[i].tv_usec)); status = dcerpc_ndr_request_recv(req[i]); torture_comment(tctx, "rounded_tdiff=%d\n", rounded_tdiff); torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "TestSleep(%d) failed", i)); torture_assert(tctx, r[i].out.result == r[i].in.seconds, talloc_asprintf(tctx, "Failed - Asked to sleep for %u seconds (server replied with %u seconds and the reply takes only %u seconds)", r[i].out.result, r[i].in.seconds, (unsigned int)diff[i].tv_sec)); torture_assert(tctx, r[i].out.result <= rounded_tdiff, talloc_asprintf(tctx, "Failed - Slept for %u seconds (but reply takes only %u.%06u seconds)", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec)); if (r[i].out.result+1 == rounded_tdiff) { torture_comment(tctx, "Slept for %u seconds (but reply takes %u.%06u seconds - busy server?)\n", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec); } else if (r[i].out.result == rounded_tdiff) { torture_comment(tctx, "Slept for %u seconds (reply takes %u.%06u seconds - ok)\n", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec); } else { torture_comment(tctx, "(Failed) - Not async - Slept for %u seconds (but reply takes %u.%06u seconds)", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec); /* TODO: let the test fail here, when we support async rpc on ncacn_np */ } } } } torture_comment(tctx, "\n"); return true; }
/* test the TestSleep interface */ static bool test_sleep(struct torture_context *tctx, struct dcerpc_pipe *p) { int i; #define ASYNC_COUNT 3 struct tevent_req *req[ASYNC_COUNT]; struct echo_TestSleep r[ASYNC_COUNT]; bool done1[ASYNC_COUNT]; bool done2[ASYNC_COUNT]; struct timeval snd[ASYNC_COUNT]; struct timeval rcv[ASYNC_COUNT]; struct timeval diff[ASYNC_COUNT]; int total_done = 0; struct dcerpc_binding_handle *b = p->binding_handle; enum dcerpc_transport_t transport; uint32_t assoc_group_id; struct dcerpc_pipe *p2 = NULL; NTSTATUS status; if (torture_setting_bool(tctx, "quick", false)) { torture_skip(tctx, "TestSleep disabled - use \"torture:quick=no\" to enable\n"); } torture_comment(tctx, "Testing TestSleep - use \"torture:quick=yes\" to disable\n"); transport = dcerpc_binding_get_transport(p->binding); assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding); torture_comment(tctx, "connect echo connection 2 with " "DCERPC_CONCURRENT_MULTIPLEX\n"); status = torture_rpc_connection_transport(tctx, &p2, &ndr_table_rpcecho, transport, assoc_group_id, DCERPC_CONCURRENT_MULTIPLEX); torture_assert_ntstatus_ok(tctx, status, "opening echo connection 2"); b = p2->binding_handle; for (i=0;i<ASYNC_COUNT;i++) { done1[i] = false; done2[i] = false; snd[i] = timeval_current(); rcv[i] = timeval_zero(); r[i].in.seconds = ASYNC_COUNT-i; req[i] = dcerpc_echo_TestSleep_r_send(tctx, tctx->ev, b, &r[i]); torture_assert(tctx, req[i], "Failed to send async sleep request\n"); tevent_req_set_callback(req[i], test_sleep_done, &done1[i]); } while (total_done < ASYNC_COUNT) { torture_assert(tctx, tevent_loop_once(tctx->ev) == 0, "Event context loop failed"); for (i=0;i<ASYNC_COUNT;i++) { if (done2[i] == false && done1[i] == true) { int rounded_tdiff; total_done++; done2[i] = true; rcv[i] = timeval_current(); diff[i] = timeval_until(&snd[i], &rcv[i]); rounded_tdiff = (int)(0.5 + diff[i].tv_sec + (1.0e-6*diff[i].tv_usec)); torture_comment(tctx, "rounded_tdiff=%d\n", rounded_tdiff); torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestSleep_r_recv(req[i], tctx), talloc_asprintf(tctx, "TestSleep(%d) failed", i)); torture_assert(tctx, r[i].out.result == r[i].in.seconds, talloc_asprintf(tctx, "Failed - Asked to sleep for %u seconds (server replied with %u seconds and the reply takes only %u seconds)", r[i].out.result, r[i].in.seconds, (unsigned int)diff[i].tv_sec)); torture_assert(tctx, r[i].out.result <= rounded_tdiff, talloc_asprintf(tctx, "Failed - Slept for %u seconds (but reply takes only %u.%06u seconds)", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec)); if (r[i].out.result+1 == rounded_tdiff) { torture_comment(tctx, "Slept for %u seconds (but reply takes %u.%06u seconds - busy server?)\n", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec); } else if (r[i].out.result == rounded_tdiff) { torture_comment(tctx, "Slept for %u seconds (reply takes %u.%06u seconds - ok)\n", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec); } else { torture_fail(tctx, talloc_asprintf(tctx, "(Failed) - Not async - Slept for %u seconds (but reply takes %u.%06u seconds)\n", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec)); } } } } torture_comment(tctx, "\n"); return true; }