18c2ecf20Sopenharmony_ci/* threadtest.c
28c2ecf20Sopenharmony_ci *		by: john stultz (johnstul@us.ibm.com)
38c2ecf20Sopenharmony_ci *		(C) Copyright IBM 2004, 2005, 2006, 2012
48c2ecf20Sopenharmony_ci *		Licensed under the GPLv2
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *  To build:
78c2ecf20Sopenharmony_ci *	$ gcc threadtest.c -o threadtest -lrt
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *   This program is free software: you can redistribute it and/or modify
108c2ecf20Sopenharmony_ci *   it under the terms of the GNU General Public License as published by
118c2ecf20Sopenharmony_ci *   the Free Software Foundation, either version 2 of the License, or
128c2ecf20Sopenharmony_ci *   (at your option) any later version.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
158c2ecf20Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
168c2ecf20Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
178c2ecf20Sopenharmony_ci *   GNU General Public License for more details.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci#include <stdio.h>
208c2ecf20Sopenharmony_ci#include <unistd.h>
218c2ecf20Sopenharmony_ci#include <stdlib.h>
228c2ecf20Sopenharmony_ci#include <sys/time.h>
238c2ecf20Sopenharmony_ci#include <pthread.h>
248c2ecf20Sopenharmony_ci#include "../kselftest.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* serializes shared list access */
278c2ecf20Sopenharmony_cipthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER;
288c2ecf20Sopenharmony_ci/* serializes console output */
298c2ecf20Sopenharmony_cipthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define MAX_THREADS 128
338c2ecf20Sopenharmony_ci#define LISTSIZE 128
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ciint done = 0;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistruct timespec global_list[LISTSIZE];
388c2ecf20Sopenharmony_ciint listcount = 0;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_civoid checklist(struct timespec *list, int size)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	int i, j;
448c2ecf20Sopenharmony_ci	struct timespec *a, *b;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	/* scan the list */
478c2ecf20Sopenharmony_ci	for (i = 0; i < size-1; i++) {
488c2ecf20Sopenharmony_ci		a = &list[i];
498c2ecf20Sopenharmony_ci		b = &list[i+1];
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci		/* look for any time inconsistencies */
528c2ecf20Sopenharmony_ci		if ((b->tv_sec <= a->tv_sec) &&
538c2ecf20Sopenharmony_ci			(b->tv_nsec < a->tv_nsec)) {
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci			/* flag other threads */
568c2ecf20Sopenharmony_ci			done = 1;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci			/*serialize printing to avoid junky output*/
598c2ecf20Sopenharmony_ci			pthread_mutex_lock(&print_lock);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci			/* dump the list */
628c2ecf20Sopenharmony_ci			printf("\n");
638c2ecf20Sopenharmony_ci			for (j = 0; j < size; j++) {
648c2ecf20Sopenharmony_ci				if (j == i)
658c2ecf20Sopenharmony_ci					printf("---------------\n");
668c2ecf20Sopenharmony_ci				printf("%lu:%lu\n", list[j].tv_sec, list[j].tv_nsec);
678c2ecf20Sopenharmony_ci				if (j == i+1)
688c2ecf20Sopenharmony_ci					printf("---------------\n");
698c2ecf20Sopenharmony_ci			}
708c2ecf20Sopenharmony_ci			printf("[FAILED]\n");
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci			pthread_mutex_unlock(&print_lock);
738c2ecf20Sopenharmony_ci		}
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/* The shared thread shares a global list
788c2ecf20Sopenharmony_ci * that each thread fills while holding the lock.
798c2ecf20Sopenharmony_ci * This stresses clock syncronization across cpus.
808c2ecf20Sopenharmony_ci */
818c2ecf20Sopenharmony_civoid *shared_thread(void *arg)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	while (!done) {
848c2ecf20Sopenharmony_ci		/* protect the list */
858c2ecf20Sopenharmony_ci		pthread_mutex_lock(&list_lock);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci		/* see if we're ready to check the list */
888c2ecf20Sopenharmony_ci		if (listcount >= LISTSIZE) {
898c2ecf20Sopenharmony_ci			checklist(global_list, LISTSIZE);
908c2ecf20Sopenharmony_ci			listcount = 0;
918c2ecf20Sopenharmony_ci		}
928c2ecf20Sopenharmony_ci		clock_gettime(CLOCK_MONOTONIC, &global_list[listcount++]);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		pthread_mutex_unlock(&list_lock);
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci	return NULL;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/* Each independent thread fills in its own
1018c2ecf20Sopenharmony_ci * list. This stresses clock_gettime() lock contention.
1028c2ecf20Sopenharmony_ci */
1038c2ecf20Sopenharmony_civoid *independent_thread(void *arg)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct timespec my_list[LISTSIZE];
1068c2ecf20Sopenharmony_ci	int count;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	while (!done) {
1098c2ecf20Sopenharmony_ci		/* fill the list */
1108c2ecf20Sopenharmony_ci		for (count = 0; count < LISTSIZE; count++)
1118c2ecf20Sopenharmony_ci			clock_gettime(CLOCK_MONOTONIC, &my_list[count]);
1128c2ecf20Sopenharmony_ci		checklist(my_list, LISTSIZE);
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci	return NULL;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#define DEFAULT_THREAD_COUNT 8
1188c2ecf20Sopenharmony_ci#define DEFAULT_RUNTIME 30
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ciint main(int argc, char **argv)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	int thread_count, i;
1238c2ecf20Sopenharmony_ci	time_t start, now, runtime;
1248c2ecf20Sopenharmony_ci	char buf[255];
1258c2ecf20Sopenharmony_ci	pthread_t pth[MAX_THREADS];
1268c2ecf20Sopenharmony_ci	int opt;
1278c2ecf20Sopenharmony_ci	void *tret;
1288c2ecf20Sopenharmony_ci	int ret = 0;
1298c2ecf20Sopenharmony_ci	void *(*thread)(void *) = shared_thread;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	thread_count = DEFAULT_THREAD_COUNT;
1328c2ecf20Sopenharmony_ci	runtime = DEFAULT_RUNTIME;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	/* Process arguments */
1358c2ecf20Sopenharmony_ci	while ((opt = getopt(argc, argv, "t:n:i")) != -1) {
1368c2ecf20Sopenharmony_ci		switch (opt) {
1378c2ecf20Sopenharmony_ci		case 't':
1388c2ecf20Sopenharmony_ci			runtime = atoi(optarg);
1398c2ecf20Sopenharmony_ci			break;
1408c2ecf20Sopenharmony_ci		case 'n':
1418c2ecf20Sopenharmony_ci			thread_count = atoi(optarg);
1428c2ecf20Sopenharmony_ci			break;
1438c2ecf20Sopenharmony_ci		case 'i':
1448c2ecf20Sopenharmony_ci			thread = independent_thread;
1458c2ecf20Sopenharmony_ci			printf("using independent threads\n");
1468c2ecf20Sopenharmony_ci			break;
1478c2ecf20Sopenharmony_ci		default:
1488c2ecf20Sopenharmony_ci			printf("Usage: %s [-t <secs>] [-n <numthreads>] [-i]\n", argv[0]);
1498c2ecf20Sopenharmony_ci			printf("	-t: time to run\n");
1508c2ecf20Sopenharmony_ci			printf("	-n: number of threads\n");
1518c2ecf20Sopenharmony_ci			printf("	-i: use independent threads\n");
1528c2ecf20Sopenharmony_ci			return -1;
1538c2ecf20Sopenharmony_ci		}
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if (thread_count > MAX_THREADS)
1578c2ecf20Sopenharmony_ci		thread_count = MAX_THREADS;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	setbuf(stdout, NULL);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	start = time(0);
1638c2ecf20Sopenharmony_ci	strftime(buf, 255, "%a, %d %b %Y %T %z", localtime(&start));
1648c2ecf20Sopenharmony_ci	printf("%s\n", buf);
1658c2ecf20Sopenharmony_ci	printf("Testing consistency with %i threads for %ld seconds: ", thread_count, runtime);
1668c2ecf20Sopenharmony_ci	fflush(stdout);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	/* spawn */
1698c2ecf20Sopenharmony_ci	for (i = 0; i < thread_count; i++)
1708c2ecf20Sopenharmony_ci		pthread_create(&pth[i], 0, thread, 0);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	while (time(&now) < start + runtime) {
1738c2ecf20Sopenharmony_ci		sleep(1);
1748c2ecf20Sopenharmony_ci		if (done) {
1758c2ecf20Sopenharmony_ci			ret = 1;
1768c2ecf20Sopenharmony_ci			strftime(buf, 255, "%a, %d %b %Y %T %z", localtime(&now));
1778c2ecf20Sopenharmony_ci			printf("%s\n", buf);
1788c2ecf20Sopenharmony_ci			goto out;
1798c2ecf20Sopenharmony_ci		}
1808c2ecf20Sopenharmony_ci	}
1818c2ecf20Sopenharmony_ci	printf("[OK]\n");
1828c2ecf20Sopenharmony_ci	done = 1;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ciout:
1858c2ecf20Sopenharmony_ci	/* wait */
1868c2ecf20Sopenharmony_ci	for (i = 0; i < thread_count; i++)
1878c2ecf20Sopenharmony_ci		pthread_join(pth[i], &tret);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	/* die */
1908c2ecf20Sopenharmony_ci	if (ret)
1918c2ecf20Sopenharmony_ci		ksft_exit_fail();
1928c2ecf20Sopenharmony_ci	return ksft_exit_pass();
1938c2ecf20Sopenharmony_ci}
194