162306a36Sopenharmony_ci/* threadtest.c 262306a36Sopenharmony_ci * by: john stultz (johnstul@us.ibm.com) 362306a36Sopenharmony_ci * (C) Copyright IBM 2004, 2005, 2006, 2012 462306a36Sopenharmony_ci * Licensed under the GPLv2 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * To build: 762306a36Sopenharmony_ci * $ gcc threadtest.c -o threadtest -lrt 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This program is free software: you can redistribute it and/or modify 1062306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 1162306a36Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or 1262306a36Sopenharmony_ci * (at your option) any later version. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful, 1562306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 1662306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1762306a36Sopenharmony_ci * GNU General Public License for more details. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci#include <stdio.h> 2062306a36Sopenharmony_ci#include <unistd.h> 2162306a36Sopenharmony_ci#include <stdlib.h> 2262306a36Sopenharmony_ci#include <sys/time.h> 2362306a36Sopenharmony_ci#include <pthread.h> 2462306a36Sopenharmony_ci#include "../kselftest.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* serializes shared list access */ 2762306a36Sopenharmony_cipthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER; 2862306a36Sopenharmony_ci/* serializes console output */ 2962306a36Sopenharmony_cipthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define MAX_THREADS 128 3362306a36Sopenharmony_ci#define LISTSIZE 128 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciint done = 0; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistruct timespec global_list[LISTSIZE]; 3862306a36Sopenharmony_ciint listcount = 0; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_civoid checklist(struct timespec *list, int size) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci int i, j; 4462306a36Sopenharmony_ci struct timespec *a, *b; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* scan the list */ 4762306a36Sopenharmony_ci for (i = 0; i < size-1; i++) { 4862306a36Sopenharmony_ci a = &list[i]; 4962306a36Sopenharmony_ci b = &list[i+1]; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* look for any time inconsistencies */ 5262306a36Sopenharmony_ci if ((b->tv_sec <= a->tv_sec) && 5362306a36Sopenharmony_ci (b->tv_nsec < a->tv_nsec)) { 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* flag other threads */ 5662306a36Sopenharmony_ci done = 1; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /*serialize printing to avoid junky output*/ 5962306a36Sopenharmony_ci pthread_mutex_lock(&print_lock); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* dump the list */ 6262306a36Sopenharmony_ci printf("\n"); 6362306a36Sopenharmony_ci for (j = 0; j < size; j++) { 6462306a36Sopenharmony_ci if (j == i) 6562306a36Sopenharmony_ci printf("---------------\n"); 6662306a36Sopenharmony_ci printf("%lu:%lu\n", list[j].tv_sec, list[j].tv_nsec); 6762306a36Sopenharmony_ci if (j == i+1) 6862306a36Sopenharmony_ci printf("---------------\n"); 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci printf("[FAILED]\n"); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci pthread_mutex_unlock(&print_lock); 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* The shared thread shares a global list 7862306a36Sopenharmony_ci * that each thread fills while holding the lock. 7962306a36Sopenharmony_ci * This stresses clock synchronization across cpus. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_civoid *shared_thread(void *arg) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci while (!done) { 8462306a36Sopenharmony_ci /* protect the list */ 8562306a36Sopenharmony_ci pthread_mutex_lock(&list_lock); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* see if we're ready to check the list */ 8862306a36Sopenharmony_ci if (listcount >= LISTSIZE) { 8962306a36Sopenharmony_ci checklist(global_list, LISTSIZE); 9062306a36Sopenharmony_ci listcount = 0; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &global_list[listcount++]); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci pthread_mutex_unlock(&list_lock); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci return NULL; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* Each independent thread fills in its own 10162306a36Sopenharmony_ci * list. This stresses clock_gettime() lock contention. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_civoid *independent_thread(void *arg) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct timespec my_list[LISTSIZE]; 10662306a36Sopenharmony_ci int count; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci while (!done) { 10962306a36Sopenharmony_ci /* fill the list */ 11062306a36Sopenharmony_ci for (count = 0; count < LISTSIZE; count++) 11162306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &my_list[count]); 11262306a36Sopenharmony_ci checklist(my_list, LISTSIZE); 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci return NULL; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define DEFAULT_THREAD_COUNT 8 11862306a36Sopenharmony_ci#define DEFAULT_RUNTIME 30 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ciint main(int argc, char **argv) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci int thread_count, i; 12362306a36Sopenharmony_ci time_t start, now, runtime; 12462306a36Sopenharmony_ci char buf[255]; 12562306a36Sopenharmony_ci pthread_t pth[MAX_THREADS]; 12662306a36Sopenharmony_ci int opt; 12762306a36Sopenharmony_ci void *tret; 12862306a36Sopenharmony_ci int ret = 0; 12962306a36Sopenharmony_ci void *(*thread)(void *) = shared_thread; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci thread_count = DEFAULT_THREAD_COUNT; 13262306a36Sopenharmony_ci runtime = DEFAULT_RUNTIME; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* Process arguments */ 13562306a36Sopenharmony_ci while ((opt = getopt(argc, argv, "t:n:i")) != -1) { 13662306a36Sopenharmony_ci switch (opt) { 13762306a36Sopenharmony_ci case 't': 13862306a36Sopenharmony_ci runtime = atoi(optarg); 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci case 'n': 14162306a36Sopenharmony_ci thread_count = atoi(optarg); 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci case 'i': 14462306a36Sopenharmony_ci thread = independent_thread; 14562306a36Sopenharmony_ci printf("using independent threads\n"); 14662306a36Sopenharmony_ci break; 14762306a36Sopenharmony_ci default: 14862306a36Sopenharmony_ci printf("Usage: %s [-t <secs>] [-n <numthreads>] [-i]\n", argv[0]); 14962306a36Sopenharmony_ci printf(" -t: time to run\n"); 15062306a36Sopenharmony_ci printf(" -n: number of threads\n"); 15162306a36Sopenharmony_ci printf(" -i: use independent threads\n"); 15262306a36Sopenharmony_ci return -1; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (thread_count > MAX_THREADS) 15762306a36Sopenharmony_ci thread_count = MAX_THREADS; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci setbuf(stdout, NULL); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci start = time(0); 16362306a36Sopenharmony_ci strftime(buf, 255, "%a, %d %b %Y %T %z", localtime(&start)); 16462306a36Sopenharmony_ci printf("%s\n", buf); 16562306a36Sopenharmony_ci printf("Testing consistency with %i threads for %ld seconds: ", thread_count, runtime); 16662306a36Sopenharmony_ci fflush(stdout); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* spawn */ 16962306a36Sopenharmony_ci for (i = 0; i < thread_count; i++) 17062306a36Sopenharmony_ci pthread_create(&pth[i], 0, thread, 0); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci while (time(&now) < start + runtime) { 17362306a36Sopenharmony_ci sleep(1); 17462306a36Sopenharmony_ci if (done) { 17562306a36Sopenharmony_ci ret = 1; 17662306a36Sopenharmony_ci strftime(buf, 255, "%a, %d %b %Y %T %z", localtime(&now)); 17762306a36Sopenharmony_ci printf("%s\n", buf); 17862306a36Sopenharmony_ci goto out; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci printf("[OK]\n"); 18262306a36Sopenharmony_ci done = 1; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ciout: 18562306a36Sopenharmony_ci /* wait */ 18662306a36Sopenharmony_ci for (i = 0; i < thread_count; i++) 18762306a36Sopenharmony_ci pthread_join(pth[i], &tret); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* die */ 19062306a36Sopenharmony_ci if (ret) 19162306a36Sopenharmony_ci ksft_exit_fail(); 19262306a36Sopenharmony_ci return ksft_exit_pass(); 19362306a36Sopenharmony_ci} 194