/* (C) 2006 Hewlett-Packard Development Company, L.P. */ /* Huschaam Hussain, TSG Solution Alliances Engineering, SAP Technology Group */ /* eMail: Huschaam.Hussain@hp.com */ #include #include #include #include #include #include #include #include #include #include #include #define LOG(level,args) if (logging >= level) { fprintf args; } char *program; pid_t pid; int processes = 4; int threads = 4; int objects = 4096; int logging = 0; int help = 0; struct threadentry { pthread_t thread; pthread_attr_t thread_attr; long arg; /* index in object[] */ long value; /* thread retval */ }; typedef struct threadentry thread_t; struct processentry { pid_t pid; int status; }; typedef struct processentry process_t; struct objectentry { uuid_t uuid; pid_t pid; pthread_t tid; int pos; }; typedef struct objectentry object_t; int objectid; object_t *object; void error(int line, char *text) { LOG(0, (stderr, "%s %d: line %d: %s: errno %d: %s\n", program, pid, line, text, errno, strerror(errno))); exit(errno); } /* of error */ void uuid_error(int line, char *text, int status) { LOG(0, (stderr, "%s %d: line %d: %s: status %d\n", program, pid, line, text, status)); exit(1); } /* of uuid error */ void pthread_error(int line, char *text, int value) { LOG(0, (stderr, "%s %d: line %d: %s: errno %d: %s\n", program, pid, line, text, value, strerror(value))); exit(value); } /* of pthread error */ void read_arguments(int argc, char *argv[]) { int status, i; unsigned long parameter; status = 0; while (!status && ((i = getopt(argc, argv, "p:t:o:l:h")) != -1)) { switch (i) { case 'p': processes = strtol(optarg, (char **)NULL, 10); status = errno != 0 || processes < 1 || processes > 1024; if (status) LOG(0, (stderr, "error: bad value for \n")); break; case 't': threads = strtol(optarg, (char **)NULL, 10); status = errno != 0 || threads < 1 || threads > 8192; if (status) LOG(0, (stderr, "error: bad value for \n")); break; case 'o': objects = strtol(optarg, (char **)NULL, 10); status = errno != 0 || objects < 1 || objects > 1048576; if (status) LOG(0, (stderr, "error: bad value for \n")); break; case 'l': logging = strtol(optarg, (char **)NULL, 10); if (errno != 0 || logging < 0 || logging > 3) { status = 1; fprintf(stderr, "error: bad value for \n"); } /* of if */ break; case 'h': help = 1; break; default: status = 1; } /* of switch */ } /* of while */ if (optind != argc) status = 1; if (status != 0 || help != 0) { LOG(0, (stderr, "usage: %s [options]\n", program)); LOG(0, (stderr, " -p [1-1024] default:%d\n", processes)); LOG(0, (stderr, " -t [1-8192] default:%d\n", threads)); LOG(0, (stderr, " -o [1-1048576] default:%d\n", objects)); LOG(0, (stderr, " -l [0|1|2|3] default:%d\n", logging)); LOG(0, (stderr, " -h display help\n")); exit(status); } /* of if */ LOG(1, (stderr, "%s %d: processes=%d\n", program, pid, processes)); LOG(1, (stderr, "%s %d: threads=%d\n", program, pid, threads)); LOG(1, (stderr, "%s %d: objects=%d\n", program, pid, objects)); LOG(1, (stderr, "%s %d: logging=%d\n", program, pid, logging)); LOG(1, (stderr, "%s %d: help=%d\n", program, pid, help)); } /* of read arguments */ void allocate_segment(int *id, void **address, size_t number, size_t size) { *id = shmget(IPC_PRIVATE, number * size, IPC_CREAT | 0600); if (*id == -1) error(__LINE__ - 2, "shmget()"); *address = shmat(*id, NULL, 0); if (*address == (void *)-1) error(__LINE__ - 2, "shmat()"); LOG(2, (stderr, "%s %d: allocate shared memory segment [id=%d,address=0x%p]\n", program, pid, *id, *address)); } /* of allocate segment */ void remove_segment(int id, void *address) { if (shmdt(address) == -1) error(__LINE__ - 1, "shmdt()"); if (shmctl(id, IPC_RMID, NULL) == -1) error(__LINE__ - 1, "shmctl()"); LOG(2, (stderr, "%s %d: remove shared memory segment [id=%d,address=0x%p]\n", program, pid, id, address)); } /* of remove segment */ void object_uuid_create(object_t * object) { uuid_generate_time(object->uuid); } /* of object uuid create */ void object_uuid_to_string(object_t * object, unsigned char **string_uuid) { uuid_unparse(object->uuid, *string_uuid); } /* of object uuid to string */ int object_uuid_compare(const void *object1, const void *object2) { uuid_t *uuid1, *uuid2; int result; uuid1 = &((object_t *) object1)->uuid; uuid2 = &((object_t *) object2)->uuid; result = uuid_compare(*uuid1, *uuid2); return (result); } /* of object uuid compare */ void * create_uuids(void *p) { long index, i; index = *((long *)p); for (i = index; i < index + objects; i++) { object_uuid_create(&object[i]); object[i].pid = pid; object[i].tid = pthread_self(); object[i].pos = i - index; } /* of for */ return (0); } /* of create uuids */ void create_threads(int index) { thread_t *thread; int i, result; pid = getpid(); thread = (thread_t *) calloc(threads, sizeof(thread_t)); if (thread == NULL) error(__LINE__ - 2, "calloc"); for (i = 0; i < threads; i++) { result = pthread_attr_init(&thread[i].thread_attr); if (result != 0) pthread_error(__LINE__, "pthread_attr_init", result); thread[i].arg = index; result = pthread_create(&thread[i].thread, &thread[i].thread_attr, &create_uuids, &thread[i].arg); if (result != 0) pthread_error(__LINE__, "pthread_create", result); LOG(2, (stderr, "%s %d: started thread [tid=%d,arg=%d]\n", program, pid, thread[i].thread, thread[i].arg)); index = index + objects; } /* of for */ for (i = 0; i < threads; i++) { result = pthread_join(thread[i].thread, (void *)&thread[i].value); if (result != 0) pthread_error(__LINE__, "pthread_join", result); LOG(2, (stderr, "%s %d: thread exited [tid=%d,value=%d]\n", program, pid, thread[i].thread, thread[i].value)); } /* of for */ free(thread); } /* of create threads */ void create_processes() { process_t *process; int i; process = (process_t *) calloc(processes, sizeof(process_t)); if (process == NULL) error(__LINE__ - 2, "calloc"); for (i = 0; i < processes; i++) { process[i].pid = fork(); switch (process[i].pid) { case -1: error(__LINE__ - 3, "fork()"); break; case 0: create_threads(i * threads * objects); exit(0); break; default: LOG(2, (stderr, "%s %d: started process [pid=%d]\n", program, pid, process[i].pid)); break; } /* of switch */ } /* of for */ for (i = 0; i < processes; i++) { if (waitpid(process[i].pid, &process[i].status, 0) == (pid_t) - 1) error(__LINE__ - 1, "waitpid()"); LOG(2, (stderr, "%s %d: process exited [pid=%d,status=%d]\n", program, pid, process[i].pid, process[i].status)); } /* of for */ free(process); } /* of create processes */ void object_dump(int i) { unsigned char uuid_string[37], *p; p = uuid_string; object_uuid_to_string(&object[i], &p); LOG(0, (stderr, "%s %d: object[%d]=[uuid=<%s>,pid=%d,tid=%d,pos=%d]\n", program, pid, i, p, object[i].pid, object[i].tid, object[i].pos)); } /* of object dump */ int main(int argc, char *argv[]) { int i, count; errno = 0; program = strdup(basename(argv[0])); pid = getpid(); read_arguments(argc, argv); allocate_segment(&objectid, (void **)&object, processes * threads * objects, sizeof(object_t)); create_processes(); if (logging >= 3) { for (i = 0; i < processes * threads * objects; i++) { object_dump(i); } /* of for */ } /* of if */ qsort(object, processes * threads * objects, sizeof(object_t), object_uuid_compare); LOG(2, (stdout, "%s %d: qsort() done\n", program, pid)); count = 0; for (i = 0; i < processes * threads * objects - 1; i++) { if (object_uuid_compare(&object[i], &object[i + 1]) == 0) { if (logging >= 1) { LOG(0, (stdout, "%s %d: objects #%d and #%d have duplicate UUIDs\n", program, pid, i, i + 1)); object_dump(i); object_dump(i + 1); } /* of if */ count = count + 1; } /* of if */ } /* of for */ remove_segment(objectid, object); if (count == 0) { LOG(0, (stdout, "test successful (no duplicate UUIDs found)\n")); } /* of if */ else { LOG(0, (stdout, "test failed (found %d duplicate UUIDs)\n", count)); } /* of else */ } /* of main */