1f08c3bdfSopenharmony_ci/****************************************************************************** 2f08c3bdfSopenharmony_ci * 3f08c3bdfSopenharmony_ci * Copyright © International Business Machines Corp., 2006, 2008 4f08c3bdfSopenharmony_ci * 5f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or modify 6f08c3bdfSopenharmony_ci * it under the terms of the GNU General Public License as published by 7f08c3bdfSopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 8f08c3bdfSopenharmony_ci * (at your option) any later version. 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * This program is distributed in the hope that it will be useful, 11f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 12f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13f08c3bdfSopenharmony_ci * the GNU General Public License for more details. 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License 16f08c3bdfSopenharmony_ci * along with this program; if not, write to the Free Software 17f08c3bdfSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18f08c3bdfSopenharmony_ci * 19f08c3bdfSopenharmony_ci * NAME 20f08c3bdfSopenharmony_ci * prio-wake.c 21f08c3bdfSopenharmony_ci * 22f08c3bdfSopenharmony_ci * DESCRIPTION 23f08c3bdfSopenharmony_ci * Test priority ordered wakeup with pthread_cond_* 24f08c3bdfSopenharmony_ci * * Steps: 25f08c3bdfSopenharmony_ci * - Creates a number of worker threads with increasing FIFO priorities 26f08c3bdfSopenharmony_ci * (by default, num worker threads = num cpus) 27f08c3bdfSopenharmony_ci * - Create a master thread 28f08c3bdfSopenharmony_ci * - The time the worker thread starts running is noted. Each of the 29f08c3bdfSopenharmony_ci * worker threads then waits on the same _condvar_. The time it 30f08c3bdfSopenharmony_ci * wakes up also noted. 31f08c3bdfSopenharmony_ci * - Once all the threads finish execution, the start and wakeup times 32f08c3bdfSopenharmony_ci * of all the threads is displayed. 33f08c3bdfSopenharmony_ci * - The output must indicate that the thread wakeup happened in a 34f08c3bdfSopenharmony_ci * priority order. 35f08c3bdfSopenharmony_ci * 36f08c3bdfSopenharmony_ci * USAGE: 37f08c3bdfSopenharmony_ci * 38f08c3bdfSopenharmony_ci * 39f08c3bdfSopenharmony_ci * AUTHOR 40f08c3bdfSopenharmony_ci * Darren Hart <dvhltc@us.ibm.com> 41f08c3bdfSopenharmony_ci * 42f08c3bdfSopenharmony_ci * HISTORY 43f08c3bdfSopenharmony_ci * 2006-Apr-26: Initial version by Darren Hart 44f08c3bdfSopenharmony_ci * 2006-May-25: Updated to use new librt.h features 45f08c3bdfSopenharmony_ci * 46f08c3bdfSopenharmony_ci *****************************************************************************/ 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_ci#include <stdio.h> 49f08c3bdfSopenharmony_ci#include <stdlib.h> 50f08c3bdfSopenharmony_ci#include <signal.h> 51f08c3bdfSopenharmony_ci#include <time.h> 52f08c3bdfSopenharmony_ci#include <pthread.h> 53f08c3bdfSopenharmony_ci#include <sched.h> 54f08c3bdfSopenharmony_ci#include <errno.h> 55f08c3bdfSopenharmony_ci#include <sys/syscall.h> 56f08c3bdfSopenharmony_ci#include <librttest.h> 57f08c3bdfSopenharmony_ci#include <libstats.h> 58f08c3bdfSopenharmony_ci 59f08c3bdfSopenharmony_civolatile int running_threads = 0; 60f08c3bdfSopenharmony_cistatic int rt_threads = 0; 61f08c3bdfSopenharmony_cistatic int locked_broadcast = 1; 62f08c3bdfSopenharmony_cistatic pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 63f08c3bdfSopenharmony_cistatic pthread_mutex_t mutex; 64f08c3bdfSopenharmony_cistatic volatile nsec_t beginrun; 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_cistatic int ret = 0; 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_civoid usage(void) 69f08c3bdfSopenharmony_ci{ 70f08c3bdfSopenharmony_ci rt_help(); 71f08c3bdfSopenharmony_ci printf("prio-wake specific options:\n"); 72f08c3bdfSopenharmony_ci printf(" -n# #: number of worker threads\n"); 73f08c3bdfSopenharmony_ci printf(" -l# 1:lock the mutex before broadcast, 0:don't\n"); 74f08c3bdfSopenharmony_ci printf(" defaults to 1\n"); 75f08c3bdfSopenharmony_ci} 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_ciint parse_args(int c, char *v) 78f08c3bdfSopenharmony_ci{ 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_ci int handled = 1; 81f08c3bdfSopenharmony_ci switch (c) { 82f08c3bdfSopenharmony_ci case 'h': 83f08c3bdfSopenharmony_ci usage(); 84f08c3bdfSopenharmony_ci exit(0); 85f08c3bdfSopenharmony_ci case 'n': 86f08c3bdfSopenharmony_ci rt_threads = atoi(v); 87f08c3bdfSopenharmony_ci break; 88f08c3bdfSopenharmony_ci case 'l': 89f08c3bdfSopenharmony_ci locked_broadcast = atoi(v); 90f08c3bdfSopenharmony_ci break; 91f08c3bdfSopenharmony_ci default: 92f08c3bdfSopenharmony_ci handled = 0; 93f08c3bdfSopenharmony_ci break; 94f08c3bdfSopenharmony_ci } 95f08c3bdfSopenharmony_ci return handled; 96f08c3bdfSopenharmony_ci} 97f08c3bdfSopenharmony_ci 98f08c3bdfSopenharmony_cistruct array { 99f08c3bdfSopenharmony_ci int *arr; 100f08c3bdfSopenharmony_ci int counter; 101f08c3bdfSopenharmony_ci}; 102f08c3bdfSopenharmony_cistruct array wakeup = { NULL, 0 }; 103f08c3bdfSopenharmony_ci 104f08c3bdfSopenharmony_civoid *master_thread(void *arg) 105f08c3bdfSopenharmony_ci{ 106f08c3bdfSopenharmony_ci int rc; 107f08c3bdfSopenharmony_ci nsec_t start; 108f08c3bdfSopenharmony_ci 109f08c3bdfSopenharmony_ci /* make sure children are started */ 110f08c3bdfSopenharmony_ci while (running_threads < rt_threads) 111f08c3bdfSopenharmony_ci usleep(1000); 112f08c3bdfSopenharmony_ci /* give the worker threads a chance to get to sleep in the kernel 113f08c3bdfSopenharmony_ci * in the unlocked broadcast case. */ 114f08c3bdfSopenharmony_ci usleep(1000); 115f08c3bdfSopenharmony_ci 116f08c3bdfSopenharmony_ci start = rt_gettime() - beginrun; 117f08c3bdfSopenharmony_ci 118f08c3bdfSopenharmony_ci printf("%08lld us: Master thread about to wake the workers\n", 119f08c3bdfSopenharmony_ci start / NS_PER_US); 120f08c3bdfSopenharmony_ci /* start the children threads */ 121f08c3bdfSopenharmony_ci if (locked_broadcast) 122f08c3bdfSopenharmony_ci rc = pthread_mutex_lock(&mutex); 123f08c3bdfSopenharmony_ci rc = pthread_cond_broadcast(&cond); 124f08c3bdfSopenharmony_ci if (locked_broadcast) 125f08c3bdfSopenharmony_ci rc = pthread_mutex_unlock(&mutex); 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_ci return NULL; 128f08c3bdfSopenharmony_ci} 129f08c3bdfSopenharmony_ci 130f08c3bdfSopenharmony_civoid *worker_thread(void *arg) 131f08c3bdfSopenharmony_ci{ 132f08c3bdfSopenharmony_ci struct sched_param sched_param; 133f08c3bdfSopenharmony_ci int policy; 134f08c3bdfSopenharmony_ci int rc; 135f08c3bdfSopenharmony_ci int mypri; 136f08c3bdfSopenharmony_ci int j; 137f08c3bdfSopenharmony_ci nsec_t start, wake; 138f08c3bdfSopenharmony_ci j = (intptr_t) arg; 139f08c3bdfSopenharmony_ci 140f08c3bdfSopenharmony_ci if (pthread_getschedparam(pthread_self(), &policy, &sched_param) != 0) { 141f08c3bdfSopenharmony_ci printf 142f08c3bdfSopenharmony_ci ("ERR: Couldn't get pthread info. Priority value wrong\n"); 143f08c3bdfSopenharmony_ci mypri = -1; 144f08c3bdfSopenharmony_ci } else { 145f08c3bdfSopenharmony_ci mypri = sched_param.sched_priority; 146f08c3bdfSopenharmony_ci } 147f08c3bdfSopenharmony_ci 148f08c3bdfSopenharmony_ci start = rt_gettime() - beginrun; 149f08c3bdfSopenharmony_ci debug(0, "%08lld us: RealtimeThread-%03d pri %03d started\n", 150f08c3bdfSopenharmony_ci start / NS_PER_US, j, mypri); 151f08c3bdfSopenharmony_ci 152f08c3bdfSopenharmony_ci rc = pthread_mutex_lock(&mutex); 153f08c3bdfSopenharmony_ci running_threads++; 154f08c3bdfSopenharmony_ci rc = pthread_cond_wait(&cond, &mutex); 155f08c3bdfSopenharmony_ci 156f08c3bdfSopenharmony_ci wake = rt_gettime() - beginrun; 157f08c3bdfSopenharmony_ci running_threads--; 158f08c3bdfSopenharmony_ci wakeup.arr[wakeup.counter++] = mypri; 159f08c3bdfSopenharmony_ci debug(0, "%08lld us: RealtimeThread-%03d pri %03d awake\n", 160f08c3bdfSopenharmony_ci wake / NS_PER_US, j, mypri); 161f08c3bdfSopenharmony_ci 162f08c3bdfSopenharmony_ci rc = pthread_mutex_unlock(&mutex); 163f08c3bdfSopenharmony_ci 164f08c3bdfSopenharmony_ci return NULL; 165f08c3bdfSopenharmony_ci} 166f08c3bdfSopenharmony_ci 167f08c3bdfSopenharmony_ciint main(int argc, char *argv[]) 168f08c3bdfSopenharmony_ci{ 169f08c3bdfSopenharmony_ci int threads_per_prio; 170f08c3bdfSopenharmony_ci int numcpus; 171f08c3bdfSopenharmony_ci int numprios; 172f08c3bdfSopenharmony_ci int prio; 173f08c3bdfSopenharmony_ci int i; 174f08c3bdfSopenharmony_ci setup(); 175f08c3bdfSopenharmony_ci 176f08c3bdfSopenharmony_ci rt_init("hn:l:", parse_args, argc, argv); 177f08c3bdfSopenharmony_ci 178f08c3bdfSopenharmony_ci if (rt_threads == 0) { 179f08c3bdfSopenharmony_ci numcpus = sysconf(_SC_NPROCESSORS_ONLN); 180f08c3bdfSopenharmony_ci rt_threads = numcpus; 181f08c3bdfSopenharmony_ci } 182f08c3bdfSopenharmony_ci wakeup.arr = malloc(rt_threads * sizeof(int)); 183f08c3bdfSopenharmony_ci wakeup.counter = 0; 184f08c3bdfSopenharmony_ci printf("\n-----------------------\n"); 185f08c3bdfSopenharmony_ci printf("Priority Ordered Wakeup\n"); 186f08c3bdfSopenharmony_ci printf("-----------------------\n"); 187f08c3bdfSopenharmony_ci printf("Worker Threads: %d\n", rt_threads); 188f08c3bdfSopenharmony_ci printf("Calling pthread_cond_broadcast() with mutex: %s\n\n", 189f08c3bdfSopenharmony_ci locked_broadcast ? "LOCKED" : "UNLOCKED"); 190f08c3bdfSopenharmony_ci 191f08c3bdfSopenharmony_ci beginrun = rt_gettime(); 192f08c3bdfSopenharmony_ci 193f08c3bdfSopenharmony_ci init_pi_mutex(&mutex); 194f08c3bdfSopenharmony_ci 195f08c3bdfSopenharmony_ci /* calculate the number of threads per priority */ 196f08c3bdfSopenharmony_ci /* we get num numprios -1 for the workers, leaving one for the master */ 197f08c3bdfSopenharmony_ci numprios = sched_get_priority_max(SCHED_FIFO) - 198f08c3bdfSopenharmony_ci sched_get_priority_min(SCHED_FIFO); 199f08c3bdfSopenharmony_ci 200f08c3bdfSopenharmony_ci threads_per_prio = rt_threads / numprios; 201f08c3bdfSopenharmony_ci if (rt_threads % numprios) 202f08c3bdfSopenharmony_ci threads_per_prio++; 203f08c3bdfSopenharmony_ci 204f08c3bdfSopenharmony_ci /* start the worker threads */ 205f08c3bdfSopenharmony_ci prio = sched_get_priority_min(SCHED_FIFO); 206f08c3bdfSopenharmony_ci for (i = rt_threads; i > 0; i--) { 207f08c3bdfSopenharmony_ci if ((i != rt_threads && (i % threads_per_prio) == 0)) 208f08c3bdfSopenharmony_ci prio++; 209f08c3bdfSopenharmony_ci create_fifo_thread(worker_thread, (void *)(intptr_t) i, prio); 210f08c3bdfSopenharmony_ci } 211f08c3bdfSopenharmony_ci 212f08c3bdfSopenharmony_ci /* start the master thread */ 213f08c3bdfSopenharmony_ci create_fifo_thread(master_thread, (void *)(intptr_t) i, ++prio); 214f08c3bdfSopenharmony_ci 215f08c3bdfSopenharmony_ci /* wait for threads to complete */ 216f08c3bdfSopenharmony_ci join_threads(); 217f08c3bdfSopenharmony_ci 218f08c3bdfSopenharmony_ci pthread_mutex_destroy(&mutex); 219f08c3bdfSopenharmony_ci 220f08c3bdfSopenharmony_ci printf("\nCriteria: Threads should be woken up in priority order\n"); 221f08c3bdfSopenharmony_ci 222f08c3bdfSopenharmony_ci for (i = 0; i < (wakeup.counter - 1); i++) { 223f08c3bdfSopenharmony_ci if (wakeup.arr[i] < wakeup.arr[i + 1]) { 224f08c3bdfSopenharmony_ci printf("FAIL: Thread %d woken before %d\n", 225f08c3bdfSopenharmony_ci wakeup.arr[i], wakeup.arr[i + 1]); 226f08c3bdfSopenharmony_ci ret++; 227f08c3bdfSopenharmony_ci } 228f08c3bdfSopenharmony_ci } 229f08c3bdfSopenharmony_ci printf("Result: %s\n", ret ? "FAIL" : "PASS"); 230f08c3bdfSopenharmony_ci return ret; 231f08c3bdfSopenharmony_ci} 232