Home | History | Annotate | Download | only in pthread_create
      1 /*
      2  * Copyright (c) 2015, Cyril Hrubis <chrubis (at) suse.cz>
      3  *
      4  * This program is free software; you can redistribute it and/or modify it
      5  * under the terms of version 2 of the GNU General Public License as
      6  * published by the Free Software Foundation.
      7  *
      8  * This program is distributed in the hope that it would be useful, but
      9  * WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     11  *
     12  * You should have received a copy of the GNU General Public License along
     13  * with this program; if not, write the Free Software Foundation, Inc.,
     14  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     15  *
     16  * This sample test aims to check the following assertion:
     17  *
     18  * pthread_create creates a thread with attributes as specified in the attr parameter.
     19  *
     20  * This test tests scheduller attributes are set correctly and schedulling works.
     21  *
     22  * The steps are:
     23  *
     24  *  - create thread with given scheduler policy and minimal priority for the
     25  *    scheduling policy
     26  *
     27  *  - get the scheduler attributes of the running thread and check
     28  *    that they are set as requested
     29  *
     30  *  - start a thread(s) with higher priority and check that the thread with
     31  *    lower priority does not finish until the high priority threads finished
     32  */
     33 
     34 
     35 /* Must be included first */
     36 #include "affinity.h"
     37 
     38 #include <pthread.h>
     39 #include <stdio.h>
     40 #include <string.h>
     41 #include <unistd.h>
     42 #include <signal.h>
     43 #include <unistd.h>
     44 #include <stdlib.h>
     45 #include <sys/time.h>
     46 #include "posixtest.h"
     47 #include "ncpu.h"
     48 
     49 static volatile sig_atomic_t flag;
     50 static int n_threads;
     51 
     52 static void alarm_handler()
     53 {
     54 	flag = 0;
     55 }
     56 
     57 void *do_work(void *arg)
     58 {
     59 	(void) arg;
     60 
     61 	while (flag)
     62 		sched_yield();
     63 
     64 	return NULL;
     65 }
     66 
     67 static void init_attr(pthread_attr_t *attr, int sched_policy, int prio)
     68 {
     69 	struct sched_param sched_param = {.sched_priority = prio};
     70 	int ret;
     71 
     72 	ret = pthread_attr_init(attr);
     73 	if (ret) {
     74 		fprintf(stderr, "pthread_attr_init(): %s\n", strerror(ret));
     75 		exit(PTS_UNRESOLVED);
     76 	}
     77 
     78 	ret = pthread_attr_setschedpolicy(attr, sched_policy);
     79 	if (ret) {
     80 		fprintf(stderr, "pthread_setschedpolicy(): %s\n", strerror(ret));
     81 		exit(PTS_UNRESOLVED);
     82 	}
     83 
     84 	ret = pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
     85 	if (ret) {
     86 		fprintf(stderr, "pthread_attr_setinheritsched(): %s\n", strerror(ret));
     87 		exit(PTS_UNRESOLVED);
     88 	}
     89 
     90 	ret = pthread_attr_setschedparam(attr, &sched_param);
     91 	if (ret) {
     92 		fprintf(stderr, "pthread_attr_setschedparam(): %s\n", strerror(ret));
     93 		exit(PTS_UNRESOLVED);
     94 	}
     95 }
     96 
     97 static void run_hp_threads(int sched_policy, int sched_prio)
     98 {
     99 	struct itimerval it;
    100 	pthread_t threads[n_threads];
    101 	pthread_attr_t attr;
    102 	int i, ret;
    103 
    104 	flag = 1;
    105 
    106 	it.it_interval.tv_sec = 0;
    107 	it.it_interval.tv_usec = 0;
    108 	it.it_value.tv_sec = n_threads / 20;
    109 	it.it_value.tv_usec = (n_threads % 20) * 50000;
    110 
    111 	init_attr(&attr, sched_policy, sched_prio);
    112 
    113 	if (signal(SIGPROF, alarm_handler) == SIG_ERR) {
    114 		perror("signal()");
    115 		exit(PTS_UNRESOLVED);
    116 	}
    117 
    118 	if (setitimer(ITIMER_PROF, &it, NULL)) {
    119 		perror("setitimer(ITIMER_VIRTUAL, ...)");
    120 		exit(PTS_UNRESOLVED);
    121 	}
    122 
    123 	for (i = 0; i < n_threads; i++) {
    124 		ret = pthread_create(&threads[i], &attr, do_work, NULL);
    125 		if (ret) {
    126 			fprintf(stderr, "pthread_create(): %s\n",
    127 			        strerror(ret));
    128 			exit(PTS_UNRESOLVED);
    129 		}
    130 	}
    131 
    132 	if (flag) {
    133 		printf("FAILED: low priority thread scheduled\n");
    134 		exit(PTS_FAIL);
    135 	}
    136 
    137 	pthread_attr_destroy(&attr);
    138 
    139 	for (i = 0; i < n_threads; i++)
    140 		pthread_join(threads[i], NULL);
    141 
    142 }
    143 
    144 struct params {
    145 	int sched_policy;
    146 	int sched_priority;
    147 };
    148 
    149 static void *do_test(void *arg)
    150 {
    151 	int ret, sched_policy;
    152 	struct sched_param param;
    153 	struct params *p = arg;
    154 
    155 	/* First check that the scheduler parameters are set correctly */
    156 	ret = pthread_getschedparam(pthread_self(), &sched_policy, &param);
    157 	if (ret) {
    158 		fprintf(stderr, "pthread_getschedparam(): %s\n", strerror(ret));
    159 		exit(PTS_UNRESOLVED);
    160 	}
    161 
    162 	if (p->sched_policy != sched_policy) {
    163 		printf("FAILED: have scheduler policy %i expected %i\n",
    164 		       sched_policy, p->sched_policy);
    165 		exit(PTS_FAIL);
    166 	}
    167 
    168 	if (p->sched_priority != param.sched_priority) {
    169 		printf("FAILED: have scheduler priority %i expected %i\n",
    170 		       p->sched_priority, param.sched_priority);
    171 		exit(PTS_FAIL);
    172 	}
    173 
    174 	/* Now check that priorities actually work */
    175 	run_hp_threads(p->sched_policy, p->sched_priority + 1);
    176 
    177 	return NULL;
    178 }
    179 
    180 struct tcase {
    181 	int sched_policy;
    182 	int prio;
    183 };
    184 
    185 enum tprio {
    186 	MIN,
    187 	HALF,
    188 	MAX_1,
    189 };
    190 
    191 struct tcase tcases[] = {
    192 	{SCHED_FIFO, MIN},
    193 	{SCHED_FIFO, HALF},
    194 	{SCHED_FIFO, MAX_1},
    195 	{SCHED_RR, MIN},
    196 	{SCHED_RR, HALF},
    197 	{SCHED_RR, MAX_1},
    198 };
    199 
    200 static int get_prio(struct tcase *self)
    201 {
    202 	switch (self->prio) {
    203 	case MIN:
    204 		return sched_get_priority_min(self->sched_policy);
    205 	break;
    206 	case HALF:
    207 		 return (sched_get_priority_min(self->sched_policy) +
    208 		         sched_get_priority_max(self->sched_policy)) / 2;
    209 	break;
    210 	case MAX_1:
    211 		return sched_get_priority_max(self->sched_policy) - 1;
    212 	break;
    213 	}
    214 
    215 	printf("Wrong self->prio %i\n", self->prio);
    216 	exit(PTS_UNRESOLVED);
    217 }
    218 
    219 static const char *sched_policy_name(int policy)
    220 {
    221 	switch (policy) {
    222 	case SCHED_FIFO:
    223 		return "SCHED_FIFO";
    224 	case SCHED_RR:
    225 		return "SCHED_RR";
    226 	default:
    227 		return "UNKNOWN";
    228 	}
    229 }
    230 
    231 int main(void)
    232 {
    233 	pthread_attr_t attr;
    234 	pthread_t th;
    235 	struct params p;
    236 	int ret;
    237 	unsigned int i;
    238 
    239 	ret = set_affinity_single();
    240 	if (ret) {
    241 		n_threads = get_ncpu();
    242 		if (n_threads == -1) {
    243 			printf("Cannot get number of CPUs\n");
    244 			return PTS_UNRESOLVED;
    245 		}
    246 		printf("INFO: Affinity not supported, running %i threads.\n",
    247 		       n_threads);
    248 	} else {
    249 		printf("INFO: Affinity works, will use only one thread.\n");
    250 		n_threads = 1;
    251 	}
    252 
    253 	for (i = 0; i < ARRAY_SIZE(tcases); i++) {
    254 		p.sched_policy = tcases[i].sched_policy;
    255 		p.sched_priority = get_prio(&tcases[i]);
    256 
    257 		init_attr(&attr, p.sched_policy, p.sched_priority);
    258 
    259 		printf("INFO: Testing %s prio %i\n",
    260 		       sched_policy_name(p.sched_policy), p.sched_priority);
    261 
    262 		ret = pthread_create(&th, &attr, do_test, &p);
    263 		if (ret) {
    264 			fprintf(stderr, "pthread_create(): %s\n", strerror(ret));
    265 			return PTS_UNRESOLVED;
    266 		}
    267 
    268 		pthread_join(th, NULL);
    269 
    270 		pthread_attr_destroy(&attr);
    271 	}
    272 
    273 	printf("Test PASSED\n");
    274 	return 0;
    275 }
    276