TEST_END static void * thd_start_reincarnated(void *arg) { tsd_t *tsd = tsd_fetch(); assert(tsd); void *p = malloc(1); assert_ptr_not_null(p, "Unexpected malloc() failure"); /* Manually trigger reincarnation. */ assert_ptr_not_null(tsd_arena_get(tsd), "Should have tsd arena set."); tsd_cleanup((void *)tsd); assert_ptr_null(*tsd_arenap_get_unsafe(tsd), "TSD arena should have been cleared."); assert_u_eq(tsd->state, tsd_state_purgatory, "TSD state should be purgatory\n"); free(p); assert_u_eq(tsd->state, tsd_state_reincarnated, "TSD state should be reincarnated\n"); p = mallocx(1, MALLOCX_TCACHE_NONE); assert_ptr_not_null(p, "Unexpected malloc() failure"); assert_ptr_null(*tsd_arenap_get_unsafe(tsd), "Should not have tsd arena set after reincarnation."); free(p); tsd_cleanup((void *)tsd); assert_ptr_null(*tsd_arenap_get_unsafe(tsd), "TSD arena should have been cleared after 2nd cleanup."); return NULL; }
static void *compare_thread(char *id) { char dn[BUFSIZ], name[40], cmpval[40]; int rc, randval, opcount; struct berval bv; void *voidrc = (void *)0; printf("Starting compare_thread %s.\n", id); opcount = 0; tsd_setup(); for (;;) { randval = get_random_id(); sprintf(name, "%d", randval); sprintf(dn, "cn=%s, " BASE, name); sprintf(cmpval, "%d", randval + random() % 3); bv.bv_val = cmpval; bv.bv_len = strlen(cmpval); printf("Thread %s: Comparing cn in entry (%s) with %s\n", id, dn, cmpval); rc = ldap_compare_ext_s(ld, dn, "cn", &bv, NULL, NULL); switch (rc) { case LDAP_COMPARE_TRUE: printf("Thread %s: entry (%s) contains cn %s\n", id, dn, cmpval); break; case LDAP_COMPARE_FALSE: printf("Thread %s: entry (%s) doesn't contain cn %s\n", id, dn, cmpval); break; default: ldap_perror(ld, "ldap_compare_ext_s"); if (rc == LDAP_SERVER_DOWN) { perror("ldap_compare_ext_s"); voidrc = (void *)1; goto compare_cleanup_and_return; } } ++opcount; if (maxops != 0 && opcount >= maxops) { break; } } compare_cleanup_and_return: printf("Thread %s: attempted %d compare operations\n", id, opcount); set_ld_error(0, NULL, NULL, NULL); /* disposes of memory */ tsd_cleanup(); free(id); return voidrc; }
static void *bind_thread(char *id) { char dn[BUFSIZ], name[40]; int rc, opcount; void *voidrc = (void *)0; printf("Starting bind_thread %s.\n", id); opcount = 0; tsd_setup(); for (;;) { sprintf(name, "%d", get_random_id()); sprintf(dn, "cn=%s, " BASE, name); printf("Thread %s: Binding as entry (%s)\n", id, dn); if ((rc = ldap_simple_bind_s(ld, dn, name)) != LDAP_SUCCESS) { ldap_perror(ld, "ldap_simple_bind_s"); if (rc == LDAP_SERVER_DOWN) { perror("ldap_simple_bind_s"); voidrc = (void *)1; goto bind_cleanup_and_return; } } else { printf("Thread %s: bound as entry (%s)\n", id, dn); } ++opcount; if (maxops != 0 && opcount >= maxops) { break; } } bind_cleanup_and_return: printf("Thread %s: attempted %d bind operations\n", id, opcount); set_ld_error(0, NULL, NULL, NULL); /* disposes of memory */ tsd_cleanup(); free(id); return voidrc; }
main(int argc, char **argv) { pthread_attr_t attr; pthread_t *threadids; void *status; struct ldap_thread_fns tfns; struct ldap_extra_thread_fns extrafns; int rc, c, errflg, i, inited_attr; int doadd, dodelete, domodify, docompare, dosearch, dobind; int option_extthreads, option_restart; int each_thread_count, thread_count; extern int optind; extern char *optarg; doadd = dodelete = domodify = docompare = dobind = dosearch = 0; option_extthreads = option_restart = 0; inited_attr = 0; errflg = 0; each_thread_count = 1; /* how many of each type of thread? */ rc = LDAP_SUCCESS; /* optimistic */ while ((c = getopt(argc, argv, "abcdmrsERi:n:o:S:")) != EOF) { switch (c) { case 'a': /* perform add operations */ ++doadd; break; case 'b': /* perform bind operations */ ++dobind; break; case 'c': /* perform compare operations */ ++docompare; break; case 'd': /* perform delete operations */ ++dodelete; break; case 'm': /* perform modify operations */ ++domodify; break; case 'r': /* use range filters in searches */ ++range_filters; break; case 's': /* perform search operations */ ++dosearch; break; case 'E': /* use extended thread functions */ ++option_extthreads; break; case 'R': /* turn on LDAP_OPT_RESTART */ ++option_restart; break; case 'i': /* highest # used for entry names */ maxid = atoi(optarg); break; case 'n': /* # threads for each operation */ if ((each_thread_count = atoi(optarg)) < 1) { fprintf(stderr, "thread count must be > 0\n"); ++errflg; } break; case 'o': /* operations to perform per thread */ if ((maxops = atoi(optarg)) < 0) { fprintf(stderr, "operation limit must be >= 0\n"); ++errflg; } break; case 'S': /* random number seed */ if (*optarg == 'r') { int seed = (int)time((time_t *)0); srandom(seed); printf("Random seed: %d\n", seed); } else { srandom(atoi(optarg)); } break; default: ++errflg; break; } } /* Check command-line syntax. */ thread_count = each_thread_count * (doadd + dodelete + domodify + dobind + docompare + dosearch); if (thread_count < 1) { fprintf(stderr, "Specify at least one of -a, -b, -c, -d, -m, or -s\n"); ++errflg; } if (errflg || argc - optind != 2) { fprintf(stderr, "usage: %s [-abcdmrsER] [-i id] [-n thr]" " [-o oplim] [-S sd] host port\n", argv[0]); fputs( "\nWhere:\n" "\t\"id\" is the highest entry id (name) to use" " (default is MAXINT)\n" "\t\"thr\" is the number of threads for each operation" " (default is 1)\n" "\t\"oplim\" is the number of ops done by each thread" " (default is infinite)\n" "\t\"sd\" is a random() number seed (default is 1). Use" " the letter r for\n" "\t\tsd to seed random() using time of day.\n" "\t\"host\" is the hostname of an LDAP directory server\n" "\t\"port\" is the TCP port of the LDAP directory server\n", stderr); fputs( "\nAnd the single character options are:\n" "\t-a\tstart thread(s) to perform add operations\n" "\t-b\tstart thread(s) to perform bind operations\n" "\t-c\tstart thread(s) to perform compare operations\n" "\t-d\tstart thread(s) to perform delete operations\n" "\t-m\tstart thread(s) to perform modify operations\n" "\t-s\tstart thread(s) to perform search operations\n" "\t-r\tuse range filters in searches\n" "\t-E\tinstall LDAP_OPT_EXTRA_THREAD_FN_PTRS\n" "\t-R\tturn on LDAP_OPT_RESTART\n", stderr); return (LDAP_PARAM_ERROR); } /* Create a key. */ if (pthread_key_create(&key, free) != 0) { perror("pthread_key_create"); } tsd_setup(); /* Allocate space for thread ids */ if ((threadids = (pthread_t *)calloc(thread_count, sizeof(pthread_t))) == NULL) { rc = LDAP_LOCAL_ERROR; goto clean_up_and_return; } /* Initialize the LDAP session. */ if ((ld = ldap_init(argv[optind], atoi(argv[optind + 1]))) == NULL) { perror("ldap_init"); rc = LDAP_LOCAL_ERROR; goto clean_up_and_return; } /* Set the function pointers for dealing with mutexes and error information. */ memset(&tfns, '\0', sizeof(struct ldap_thread_fns)); tfns.ltf_mutex_alloc = (void *(*)(void))my_mutex_alloc; tfns.ltf_mutex_free = (void (*)(void *))my_mutex_free; tfns.ltf_mutex_lock = (int (*)(void *))pthread_mutex_lock; tfns.ltf_mutex_unlock = (int (*)(void *))pthread_mutex_unlock; tfns.ltf_get_errno = get_errno; tfns.ltf_set_errno = set_errno; tfns.ltf_get_lderrno = get_ld_error; tfns.ltf_set_lderrno = set_ld_error; tfns.ltf_lderrno_arg = NULL; /* Set up this session to use those function pointers. */ rc = ldap_set_option(ld, LDAP_OPT_THREAD_FN_PTRS, (void *)&tfns); if (rc < 0) { rc = ldap_get_lderrno(ld, NULL, NULL); fprintf(stderr, "ldap_set_option (LDAP_OPT_THREAD_FN_PTRS): %s\n", ldap_err2string(rc)); goto clean_up_and_return; } if (option_extthreads) { /* Set the function pointers for working with semaphores. */ memset(&extrafns, '\0', sizeof(struct ldap_extra_thread_fns)); extrafns.ltf_mutex_trylock = (int (*)(void *))pthread_mutex_trylock; extrafns.ltf_sema_alloc = (void *(*)(void))my_sema_alloc; extrafns.ltf_sema_free = (void (*)(void *))my_sema_free; extrafns.ltf_sema_wait = (int (*)(void *))my_sema_wait; extrafns.ltf_sema_post = (int (*)(void *))my_sema_post; /* Set up this session to use those function pointers. */ if (ldap_set_option(ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS, (void *)&extrafns) != 0) { rc = ldap_get_lderrno(ld, NULL, NULL); ldap_perror(ld, "ldap_set_option" " (LDAP_OPT_EXTRA_THREAD_FN_PTRS)"); goto clean_up_and_return; } } if (option_restart && ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON) != 0) { rc = ldap_get_lderrno(ld, NULL, NULL); ldap_perror(ld, "ldap_set_option(LDAP_OPT_RESTART)"); goto clean_up_and_return; } /* Attempt to bind to the server. */ rc = ldap_simple_bind_s(ld, NAME, PASSWORD); if (rc != LDAP_SUCCESS) { fprintf(stderr, "ldap_simple_bind_s: %s\n", ldap_err2string(rc)); goto clean_up_and_return; } /* Initialize the attribute. */ if (pthread_attr_init(&attr) != 0) { perror("pthread_attr_init"); rc = LDAP_LOCAL_ERROR; goto clean_up_and_return; } ++inited_attr; /* Specify that the threads are joinable. */ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); /* Create all the requested threads */ thread_count = 0; if (domodify) { for (i = 0; i < each_thread_count; ++i) { if (pthread_create(&threadids[thread_count], &attr, modify_thread, get_id_str(thread_count)) != 0) { perror("pthread_create modify_thread"); rc = LDAP_LOCAL_ERROR; goto clean_up_and_return; } ++thread_count; } } if (doadd) { for (i = 0; i < each_thread_count; ++i) { if (pthread_create(&threadids[thread_count], &attr, add_thread, get_id_str(thread_count)) != 0) { perror("pthread_create add_thread"); rc = LDAP_LOCAL_ERROR; goto clean_up_and_return; } ++thread_count; } } if (dodelete) { for (i = 0; i < each_thread_count; ++i) { if (pthread_create(&threadids[thread_count], &attr, delete_thread, get_id_str(thread_count)) != 0) { perror("pthread_create delete_thread"); rc = LDAP_LOCAL_ERROR; goto clean_up_and_return; } ++thread_count; } } if (dobind) { for (i = 0; i < each_thread_count; ++i) { if (pthread_create(&threadids[thread_count], &attr, bind_thread, get_id_str(thread_count)) != 0) { perror("pthread_create bind_thread"); rc = LDAP_LOCAL_ERROR; goto clean_up_and_return; } ++thread_count; } } if (docompare) { for (i = 0; i < each_thread_count; ++i) { if (pthread_create(&threadids[thread_count], &attr, compare_thread, get_id_str(thread_count)) != 0) { perror("pthread_create compare_thread"); rc = LDAP_LOCAL_ERROR; goto clean_up_and_return; } ++thread_count; } } if (dosearch) { for (i = 0; i < each_thread_count; ++i) { if (pthread_create(&threadids[thread_count], &attr, search_thread, get_id_str(thread_count)) != 0) { perror("pthread_create search_thread"); rc = LDAP_LOCAL_ERROR; goto clean_up_and_return; } ++thread_count; } } /* Wait until these threads exit. */ for (i = 0; i < thread_count; ++i) { pthread_join(threadids[i], &status); } clean_up_and_return: if (ld != NULL) { set_ld_error(0, NULL, NULL, NULL); /* disposes of memory */ ldap_unbind(ld); } if (threadids != NULL) { free(threadids); } if (inited_attr) { pthread_attr_destroy(&attr); } tsd_cleanup(); return (rc); }
static void *search_thread(char *id) { LDAPMessage *res, *entry; char *dn, filter[40]; int rc, opcount; void *voidrc = (void *)0; printf("Starting search_thread %s.\n", id); opcount = 0; tsd_setup(); for (;;) { if (range_filters) { switch (get_random_id() % 3) { case 0: sprintf(filter, "(cn>=%d)", get_random_id()); break; case 1: sprintf(filter, "(cn<=%d)", get_random_id()); break; case 2: sprintf(filter, "(&(cn>=%d)(cn<=%d))", get_random_id(), get_random_id()); break; } } else { sprintf(filter, "cn=%d", get_random_id()); } printf("Thread %s: Searching for entry (%s)\n", id, filter); res = NULL; if ((rc = ldap_search_ext_s(ld, BASE, SCOPE, filter, NULL, 0, NULL, NULL, NULL, 0, &res)) != LDAP_SUCCESS) { ldap_perror(ld, "ldap_search_ext_s"); if (rc == LDAP_SERVER_DOWN) { perror("ldap_search_ext_s"); voidrc = (void *)1; goto search_cleanup_and_return; } } if (res != NULL) { entry = ldap_first_entry(ld, res); if (entry == NULL) { printf("Thread %s: found no entries\n", id); } else { dn = ldap_get_dn(ld, entry); printf("Thread %s: found entry (%s); %d total\n", id, dn == NULL ? "(Null)" : dn, ldap_count_entries(ld, res)); ldap_memfree(dn); } ldap_msgfree(res); } ++opcount; if (maxops != 0 && opcount >= maxops) { break; } } search_cleanup_and_return: printf("Thread %s: attempted %d search operations\n", id, opcount); set_ld_error(0, NULL, NULL, NULL); /* disposes of memory */ tsd_cleanup(); free(id); return voidrc; }
static void *delete_thread(char *id) { LDAPMessage *res; char dn[BUFSIZ], name[40]; int num_entries, msgid, rc, parse_rc, finished, opcount; struct timeval zerotime; void *voidrc = (void *)0; zerotime.tv_sec = zerotime.tv_usec = 0L; printf("Starting delete_thread %s.\n", id); opcount = 0; tsd_setup(); rc = ldap_search_ext(ld, BASE, SCOPE, "(objectclass=*)", NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgid); if (rc != LDAP_SUCCESS) { fprintf(stderr, "Thread %s error: Delete thread: " "ldap_search_ext: %s\n", id, ldap_err2string(rc)); exit(1); } finished = 0; num_entries = 0; while (!finished) { rc = ldap_result(ld, msgid, LDAP_MSG_ONE, &zerotime, &res); switch (rc) { case -1: rc = ldap_get_lderrno(ld, NULL, NULL); fprintf(stderr, "ldap_result: %s\n", ldap_err2string(rc)); exit(1); break; case 0: break; /* Keep track of the number of entries found. */ case LDAP_RES_SEARCH_ENTRY: num_entries++; break; case LDAP_RES_SEARCH_REFERENCE: break; case LDAP_RES_SEARCH_RESULT: finished = 1; parse_rc = ldap_parse_result(ld, res, &rc, NULL, NULL, NULL, NULL, 1); if (parse_rc != LDAP_SUCCESS) { fprintf(stderr, "Thread %s error: can't parse result code.\n", id); exit(1); } else { if (rc != LDAP_SUCCESS) { fprintf(stderr, "Thread %s error: ldap_search: %s\n", id, ldap_err2string(rc)); } else { printf("Thread %s: Got %d results.\n", id, num_entries); } } break; default: break; } } for (;;) { sprintf(name, "%d", get_random_id()); sprintf(dn, "cn=%s, " BASE, name); printf("Thread %s: Deleting entry (%s)\n", id, dn); if ((rc = ldap_delete_ext_s(ld, dn, NULL, NULL)) != LDAP_SUCCESS) { ldap_perror(ld, "ldap_delete_ext_s"); if (rc == LDAP_SERVER_DOWN) { perror("ldap_delete_ext_s"); voidrc = (void *)1; goto delete_cleanup_and_return; } } ++opcount; if (maxops != 0 && opcount >= maxops) { break; } } delete_cleanup_and_return: printf("Thread %s: attempted %d delete operations\n", id, opcount); set_ld_error(0, NULL, NULL, NULL); /* disposes of memory */ tsd_cleanup(); free(id); return voidrc; }
static void *add_thread(char *id) { LDAPMod mod[4]; LDAPMod *mods[5]; char dn[BUFSIZ], name[40]; char *cnvals[2], *snvals[2], *pwdvals[2], *ocvals[3]; int i, rc, opcount; void *voidrc = (void *)0; printf("Starting add_thread %s.\n", id); opcount = 0; tsd_setup(); for (i = 0; i < 4; i++) { mods[i] = &mod[i]; } mods[4] = NULL; mod[0].mod_op = 0; mod[0].mod_type = "cn"; mod[0].mod_values = cnvals; cnvals[1] = NULL; mod[1].mod_op = 0; mod[1].mod_type = "sn"; mod[1].mod_values = snvals; snvals[1] = NULL; mod[2].mod_op = 0; mod[2].mod_type = "objectclass"; mod[2].mod_values = ocvals; ocvals[0] = "top"; ocvals[1] = "person"; ocvals[2] = NULL; mod[3].mod_op = 0; mod[3].mod_type = "userPassword"; mod[3].mod_values = pwdvals; pwdvals[1] = NULL; mods[4] = NULL; for (;;) { sprintf(name, "%d", get_random_id()); sprintf(dn, "cn=%s, " BASE, name); cnvals[0] = name; snvals[0] = name; pwdvals[0] = name; printf("Thread %s: Adding entry (%s)\n", id, dn); rc = ldap_add_ext_s(ld, dn, mods, NULL, NULL); if (rc != LDAP_SUCCESS) { fprintf(stderr, "ldap_add_ext_s: %s\n", ldap_err2string(rc)); if (rc == LDAP_SERVER_DOWN) { perror("ldap_add_ext_s"); voidrc = (void *)1; goto add_cleanup_and_return; } } ++opcount; if (maxops != 0 && opcount >= maxops) { break; } } add_cleanup_and_return: printf("Thread %s: attempted %d add operations\n", id, opcount); set_ld_error(0, NULL, NULL, NULL); /* disposes of memory */ tsd_cleanup(); free(id); return voidrc; }
static void *modify_thread(char *id) { LDAPMessage *res; LDAPMessage *e; int i, modentry, num_entries, msgid, parse_rc, finished; int rc, opcount; LDAPMod mod; LDAPMod *mods[2]; char *vals[2]; char *dn; ldapmsgwrapper *list, *lmwp, *lastlmwp; struct timeval zerotime; void *voidrc = (void *)0; zerotime.tv_sec = zerotime.tv_usec = 0L; printf("Starting modify_thread %s.\n", id); opcount = 0; tsd_setup(); rc = ldap_search_ext(ld, BASE, SCOPE, "(objectclass=*)", NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgid); if (rc != LDAP_SUCCESS) { fprintf(stderr, "Thread %s error: Modify thread: " "ldap_search_ext: %s\n", id, ldap_err2string(rc)); exit(1); } list = lastlmwp = NULL; finished = 0; num_entries = 0; while (!finished) { rc = ldap_result(ld, msgid, LDAP_MSG_ONE, &zerotime, &res); switch (rc) { case -1: rc = ldap_get_lderrno(ld, NULL, NULL); fprintf(stderr, "ldap_result: %s\n", ldap_err2string(rc)); exit(1); break; case 0: break; /* Keep track of the number of entries found. */ case LDAP_RES_SEARCH_ENTRY: num_entries++; if ((lmwp = (ldapmsgwrapper *)malloc(sizeof(ldapmsgwrapper))) == NULL) { fprintf(stderr, "Thread %s: Modify thread: Cannot malloc\n", id); exit(1); } lmwp->lmw_messagep = res; lmwp->lmw_next = NULL; if (lastlmwp == NULL) { list = lastlmwp = lmwp; } else { lastlmwp->lmw_next = lmwp; } lastlmwp = lmwp; break; case LDAP_RES_SEARCH_REFERENCE: break; case LDAP_RES_SEARCH_RESULT: finished = 1; parse_rc = ldap_parse_result(ld, res, &rc, NULL, NULL, NULL, NULL, 1); if (parse_rc != LDAP_SUCCESS) { fprintf(stderr, "Thread %s error: can't parse result code.\n", id); exit(1); } else { if (rc != LDAP_SUCCESS) { fprintf(stderr, "Thread %s error: ldap_search: %s\n", id, ldap_err2string(rc)); } else { printf("Thread %s: Got %d results.\n", id, num_entries); } } break; default: break; } } mods[0] = &mod; mods[1] = NULL; vals[0] = "bar"; vals[1] = NULL; for (;;) { modentry = random() % num_entries; for (i = 0, lmwp = list; lmwp != NULL && i < modentry; i++, lmwp = lmwp->lmw_next) { /* NULL */ } if (lmwp == NULL) { fprintf(stderr, "Thread %s: Modify thread could not find entry %d of %d\n", id, modentry, num_entries); continue; } e = lmwp->lmw_messagep; printf("Thread %s: Modify thread picked entry %d of %d\n", id, i, num_entries); dn = ldap_get_dn(ld, e); mod.mod_op = LDAP_MOD_REPLACE; mod.mod_type = "description"; mod.mod_values = vals; printf("Thread %s: Modifying (%s)\n", id, dn); rc = ldap_modify_ext_s(ld, dn, mods, NULL, NULL); if (rc != LDAP_SUCCESS) { fprintf(stderr, "ldap_modify_ext_s: %s\n", ldap_err2string(rc)); if (rc == LDAP_SERVER_DOWN) { perror("ldap_modify_ext_s"); voidrc = (void *)1; goto modify_cleanup_and_return; } } free(dn); ++opcount; if (maxops != 0 && opcount >= maxops) { break; } } modify_cleanup_and_return: printf("Thread %s: attempted %d modify operations\n", id, opcount); set_ld_error(0, NULL, NULL, NULL); /* disposes of memory */ tsd_cleanup(); free(id); return voidrc; }