/** Shuffle an index to avoid excessive lock contention in models where topologically adjacent objects are loaded sequentially **/ void index_shuffle(INDEX *index) /**< the index to shuffle */ { int i, size = index->last_used - index->first_used; for (i=0; i<size; i++) list_shuffle(index->ordinal[i]); output_verbose("shuffled %d lists in index %d", size, index->id); }
/* * Write a binary tree node to disk. */ int pdb_write_tree_node_cb(struct pdb* dbptr, FILE* fptr, struct pdb_node_t* nptr, int tabs) { struct binaryTree* tptr; struct linkList* lptr; struct linkNode* lnptr; /* * Create a list from the tree so we can iterate through it. */ tptr = nptr->data; lptr = list_create(); tree_to_list(tptr, lptr); lnptr = lptr->root; /* * Shuffle tree (if set). */ if (pdb_is_set(dbptr, PDB_WRITE_SHUFFLE)) list_shuffle(lptr); /* * Set PDB_WRITE_NODE_FIRST_ID as the first in the list * if PDB_WRITE_NODE_FIRST is set. * Only if root node. */ if (!tabs) { if (pdb_is_set(dbptr, PDB_WRITE_NODE_FIRST)) { while (lnptr) { nptr = lnptr->data; if (!strcmp(nptr->id, PDB_WRITE_NODE_FIRST_ID)) { list_free_node(lptr, lnptr, 0, NULL); list_add_node_front(lptr, nptr); break; } lnptr = lnptr->next; } } } /* * Write all children to disk. */ lnptr = lptr->root; while (lnptr) { nptr = lnptr->data; if (!pdb_standard_write_node(dbptr, fptr, nptr, tabs)) { list_free(lptr, 0, NULL); return 0; } lnptr = lnptr->next; } /* * Free temp list (but not data). */ list_free(lptr, 0, NULL); return 1; }
THREAD_RAC buffer_thread(void *arg) { size_t cur = 0; buf_str *ctx = arg; volatile unsigned char *sync = ctx->p.update + ctx->cur_id; MUTEX_LOCK(ctx->p.mutex + ctx->cur_id); *sync = 0xFF; while (*sync); while(1) { if (force_exit_signal) break; buffering_do(ctx, cur++); if (!ctx->list[cur].n) { list_shuffle(ctx->list); cur = 0; } } MUTEX_UNLOCK(ctx->p.mutex + ctx->cur_id); return 0; }
int main(int argc, char **argv) { int i; buf_str ctx; memset(&ctx, 0, sizeof(buf_str)); ctx.p.period = PERIOD_SIZE; ctx.p.buf_max = 0xFFF;//TODO variable buf ctx.p.mutex = malloc(sizeof(MUTEX_T) * (ctx.p.buf_max + 1)); for (i = 0; i <= ctx.p.buf_max; i++) { MUTEX_INIT(ctx.p.mutex + i); } ctx.p.update = malloc(sizeof(unsigned char) * (ctx.p.buf_max + 1)); memset(ctx.p.update, 0, sizeof(unsigned char) * (ctx.p.buf_max + 1)); ctx.p.buf = malloc((ctx.p.buf_max + 1) * ctx.p.period * CHANNELS * BITS / 8); //FIXME memory allocation failed ctx.list = listing(argv + 1); if(!ctx.list) force_exit_signal = 1; else list_shuffle(ctx.list); THREAD_T play, buffer; #ifndef _WIN32 pthread_attr_t rt; struct sched_param p = {}; p.sched_priority = sched_get_priority_max(SCHED_RR); pthread_attr_init(&rt); pthread_attr_setinheritsched(&rt, PTHREAD_EXPLICIT_SCHED); pthread_attr_setschedpolicy(&rt, SCHED_RR); pthread_attr_setschedparam(&rt, &p); #endif CREATE_THREAD(buffer, buffer_thread, &ctx); CREATE_THREAD_RT(play, play_thread, &ctx.p, &rt); console(); JOIN_THREAD(buffer); JOIN_THREAD(play); list_full_remove(ctx.list); for (i = 0; i <= ctx.p.buf_max; i++) { MUTEX_DESTROY(ctx.p.mutex + i); } free(ctx.p.mutex); free(ctx.p.update); free(ctx.p.buf); return 0; }
listhead_t *run_net_tests(int concurrency, char *sourceip4, char *sourceip6) { int maxfd; list_shuffle(pendingtests); /* * Determine how many tests can run in parallel. * If no --concurrency set by user, default to (FD_SETSIZE / 4) - typically 256. * But never go above the ressource limit that is set, or above FD_SETSIZE. * And we save some fd's - 20 - for stdio, libs etc. */ { int absmaxconcurrency = (FD_SETSIZE - 20); struct rlimit lim; getrlimit(RLIMIT_NOFILE, &lim); if ((lim.rlim_cur > 20) && ((lim.rlim_cur - 20) < absmaxconcurrency)) absmaxconcurrency = (lim.rlim_cur - 20); if (concurrency == 0) concurrency = (FD_SETSIZE / 4); if (concurrency > absmaxconcurrency) concurrency = absmaxconcurrency; } /* Loop to process data */ do { fd_set fdread, fdwrite; int n; struct timeval tmo; myconn_t *rec; listitem_t *pcur, *pnext; int lookupsposted = 0; dbgprintf("*** Starting test loop ***\n"); /* Start some more tests */ pcur = pendingtests->head; while (pcur && (activetests->len < concurrency) && (lookupsposted < concurrency)) { rec = (myconn_t *)pcur->data; dbgprintf(" Test: %s\n", rec->testspec); /* * Must save the pointer to the next pending test now, * since we may move the current item from the pending * list to the active list before going to the next * item in the pending-list. */ pnext = pcur->next; if (rec->netparams.lookupstatus == LOOKUP_NEEDED) { dbgprintf(" LOOKUP_NEEDED\n"); lookupsposted++; dns_lookup(rec); } if ((rec->netparams.lookupstatus == LOOKUP_ACTIVE) || (rec->netparams.lookupstatus == LOOKUP_NEEDED)) { /* DNS lookup in progress, skip this test until lookup completes */ dbgprintf(" lookup in progress: %s\n", (rec->netparams.lookupstatus == LOOKUP_ACTIVE) ? "ACTIVE" : "NEEDED"); pcur = pnext; continue; } else if (rec->netparams.lookupstatus == LOOKUP_FAILED) { /* DNS lookup determined that this host does not have a valid IP. */ dbgprintf(" LOOKUP_FAILED\n"); switch (dnsstrategy) { case DNS_STRATEGY_HOSTNAME: /* DNS failed -> test failed */ list_item_move(donetests, pcur, rec->testspec); rec->talkresult = TALK_CANNOT_RESOLVE; break; case DNS_STRATEGY_STANDARD: case DNS_STRATEGY_IP: /* This one cannot really happen */ /* Use IP from hosts.cfg, if it is valid */ if (!conn_null_ip(xmh_item(rec->hostinfo, XMH_IP))) { xfree(rec->netparams.destinationip); rec->netparams.destinationip = strdup(xmh_item(rec->hostinfo, XMH_IP)); rec->netparams.lookupstatus = LOOKUP_COMPLETED; } else { list_item_move(donetests, pcur, rec->testspec); rec->talkresult = TALK_CANNOT_RESOLVE; } break; } pcur = pnext; continue; } switch (rec->talkprotocol) { case TALK_PROTO_PLAIN: case TALK_PROTO_HTTP: case TALK_PROTO_NTP: case TALK_PROTO_LDAP: case TALK_PROTO_EXTERNAL: if (!rec->teststarttime) rec->teststarttime = getcurrenttime(NULL); dbgprintf(" conn_prepare_connection()\n"); if (!rec->netparams.sourceip && (sourceip4 || sourceip6)) { switch (conn_is_ip(rec->netparams.destinationip)) { case 4: rec->netparams.sourceip = sourceip4; break; case 6: rec->netparams.sourceip = sourceip6; break; } } if (conn_prepare_connection(rec->netparams.destinationip, rec->netparams.destinationport, rec->netparams.socktype, rec->netparams.sourceip, rec->netparams.sslhandling, rec->netparams.sslname, rec->netparams.sslcertfn, rec->netparams.sslkeyfn, rec->timeout*1000000, rec->netparams.callback, rec)) { dbgprintf("\tmoved to activetests, target %s, timeout %d\n", rec->netparams.destinationip, rec->timeout); list_item_move(activetests, pcur, rec->testspec); } else { dbgprintf("\tmoved to failedtests\n"); rec->talkresult = TALK_CONN_FAILED; list_item_move(donetests, pcur, rec->testspec); } break; case TALK_PROTO_DNSQUERY: dbgprintf(" dns_start_query()\n"); if (dns_start_query(rec, rec->netparams.destinationip)) { dbgprintf("\tmoved to activetests\n"); list_item_move(activetests, pcur, rec->testspec); } else { dbgprintf("\tmoved to failedtests\n"); rec->talkresult = TALK_CONN_FAILED; list_item_move(donetests, pcur, rec->testspec); } break; case TALK_PROTO_PING: dbgprintf(" PING test, queued\n"); rec->talkresult = TALK_OK; list_item_move(donetests, pcur, rec->testspec); break; default: dbgprintf(" Huh?\n"); break; } pcur = pnext; } maxfd = conn_fdset(&fdread, &fdwrite); // dbgprintf("Setting up select - conn_fdset has maxfd=%d\n", maxfd); dns_add_active_fds(activetests, &maxfd, &fdread, &fdwrite); // dbgprintf("Setting up select - dns_add_active_fds set maxfd=%d\n", maxfd); if (maxfd > 0) { tmo.tv_sec = 1; tmo.tv_usec = 0; n = select(maxfd+1, &fdread, &fdwrite, NULL, &tmo); if (n < 0) { if (errno != EINTR) { errprintf("FATAL: select() returned error %s\n", strerror(errno)); return NULL; } } conn_process_active(&fdread, &fdwrite); dns_process_active(activetests, &fdread, &fdwrite); } conn_trimactive(); dns_finish_queries(activetests); dbgprintf("Active: %d, pending: %d\n", activetests->len, pendingtests->len); } while ((activetests->len + pendingtests->len) > 0); dns_finish_queries(donetests); return donetests; }