blob: 46b5cee8f0d81002c3d17b7a8f5a0409120b3de5 [file] [log] [blame]
/*
*
* Copyright (c) Novell Inc. 2011
*
* This program is free software; you can redistribute it and/or modify
* it under the terms in version 2 of the GNU General Public License as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Peter W. Morreale <pmorreale AT novell DOT com>
*
* Date: 20/05/2011
*/
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <posixtest.h>
/* Priorities for the threads, must be unique, non-zero, and ordered */
#define PRIO_HIGH 20
#define PRIO_MED 10
#define PRIO_LOW 5
static int priorities[3];
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t c_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static int thread_started;
#define ERR_MSG(f, rc) printf("Failed: function: %s status: %s(%u)\n", \
f, strerror(rc), rc)
static void *thread_func(void *data)
{
struct sched_param sp;
int policy;
int rc;
rc = pthread_getschedparam(pthread_self(), &policy, &sp);
if (rc) {
ERR_MSG("pthread_getschedparam()", rc);
goto done;
}
thread_started = 1;
rc = pthread_cond_signal(&cond);
if (rc) {
ERR_MSG("pthread_cond_signal()", rc);
goto done;
}
rc = pthread_mutex_lock(&mutex);
if (rc) {
ERR_MSG("pthread_mutex_lock()", rc);
goto done;
}
/* Stuff the priority in execution order */
if (!priorities[0])
priorities[0] = sp.sched_priority;
else if (!priorities[1])
priorities[1] = sp.sched_priority;
else
priorities[2] = sp.sched_priority;
rc = pthread_mutex_unlock(&mutex);
if (rc) {
ERR_MSG("pthread_mutex_unlock()", rc);
goto done;
}
done:
return (void *) (long) rc;
}
static int create_thread(int prio, pthread_t *tid)
{
int rc;
char *func;
struct sched_param sp;
pthread_attr_t attr;
func = "pthread_attr_init()";
rc = pthread_attr_init(&attr);
if (rc != 0)
goto done;
func = "pthread_attr_setschedpolicy()";
rc = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
if (rc != 0)
goto error;
func = "pthread_attr_setinheritsched()";
rc = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
if (rc != 0)
goto error;
func = "pthread_attr_setschedparam()";
sp.sched_priority = prio;
rc = pthread_attr_setschedparam(&attr, &sp);
if (rc != 0)
goto error;
thread_started = 0;
rc = pthread_create(tid, &attr, thread_func, NULL);
if (rc) {
ERR_MSG("pthread_create()", rc);
goto error;
}
while (!thread_started) {
func = "pthread_mutex_lock()";
rc = pthread_mutex_lock(&c_mutex);
if (rc)
goto error;
func = "pthread_cond_wait()";
rc = pthread_cond_wait(&cond, &c_mutex);
if (rc)
goto unlock;
func = "pthread_mutex_unlock()";
rc = pthread_mutex_unlock(&c_mutex);
if (rc)
goto error;
}
pthread_attr_destroy(&attr);
return 0;
unlock:
(void) pthread_mutex_unlock(&c_mutex);
error:
pthread_attr_destroy(&attr);
done:
ERR_MSG(func, rc);
return -1;
}
int main(void)
{
int status;
int rc;
void *r1;
void *r2;
void *r3;
pthread_t t1;
pthread_t t2;
pthread_t t3;
status = PTS_UNRESOLVED;
rc = pthread_mutex_lock(&mutex);
if (rc) {
ERR_MSG("pthread_mutex_lock()", rc);
goto done;
}
rc = create_thread(PRIO_LOW, &t3);
if (rc)
goto done;
rc = create_thread(PRIO_MED, &t2);
if (rc)
goto done;
rc = create_thread(PRIO_HIGH, &t1);
if (rc)
goto done;
rc = pthread_mutex_unlock(&mutex);
if (rc)
ERR_MSG("pthread_mutex_unlock()", rc);
rc = pthread_join(t1, &r1);
if (rc) {
ERR_MSG("pthread_join(t1)", rc);
goto done;
}
rc = pthread_join(t2, &r2);
if (rc) {
ERR_MSG("pthread_join(t2)", rc);
goto done;
}
rc = pthread_join(t3, &r3);
if (rc) {
ERR_MSG("pthread_join(t3)", rc);
goto done;
}
/* Threads fail? */
if ((long) r1 || (long) r2 || (long) r2)
goto done;
/* priorities must be high to low */
status = PTS_FAIL;
if (priorities[0] != PRIO_HIGH)
printf("Failed: first is prio: %u, should be: %u\n",
priorities[0], PRIO_HIGH);
else if (priorities[1] != PRIO_MED)
printf("Failed: second is prio: %u, should be: %u\n",
priorities[1], PRIO_MED);
else if (priorities[2] != PRIO_LOW)
printf("Failed: third is prio: %u, should be: %u\n",
priorities[2], PRIO_LOW);
else
status = PTS_PASS;
done:
if (status == PTS_PASS)
printf("Test PASSED\n");
return status;
}