/* * Copyright (c) 2003-2004, Intel Corporation. All rights reserved. * This file is licensed under the GPL license. For the full content * of this license, see the COPYING file at the top level of this * source tree. * adam.li@intel.com 2004-03 */ /* * If the Process Scheduling option is supported, the thread to be unblocked * shall be chosen in a manner appropriate to the scheduling policies * and parameters in effect for the blocked threads. * In the case of the schedulers SCHED_FIFO and SCHED_RR, the highest * priority waiting thread shall be unblocked, and if there is * more than one highest priority thread blocked waiting for the semaphore, * then the highest priority thread that has been waiting the * longest shall be unblocked. * If the Process Scheduling option is not defined, the choice of a thread * to unblock is unspecified. * * Test Steps: * Here we test SCHED_FIFO * 1. Parent locks a semaphore, it has highest priority P0. * 2. It forks 2 child processes 1, 2, as for priority P1, P2, P0 > P2 > P1 * 3. The children lock the semaphore. * Make sure the two children are waiting. * 4. Parent forks another child 3, with priority P3, P3 = P2, it locks * the semaphore too. * 5. Parent unlocks the semaphore, make sure the children * wake up in the order of 2 -> 3 -> 1 */ #include #include #include #include #include #include #include "posixtest.h" #include #include #include #include #define TEST "8-1" #define FUNCTION "sem_wait" #define ERROR_PREFIX "unexpected error: " FUNCTION " " TEST ": " static char semname[20]; static char semname_1[20]; /* Used to record state */ /* set my schedule priority to @priority */ int set_my_prio(int priority) { struct sched_param sp; sp.sched_priority = priority; /* Set priority */ if (sched_setscheduler(0, SCHED_FIFO, &sp) == -1) { perror("Error at sched_setscheduler()\n"); return -1; } return 0; } int get_my_prio() { struct sched_param sp; if (sched_getparam(0, &sp) == -1) { perror("Error at sched_getparam()\n"); return -1; } return sp.sched_priority; } int child_fn(int priority, int id) { sem_t *sem, *sem_1; if (set_my_prio(priority) == -1) exit(-1); sem = sem_open(semname, 0); if( sem == SEM_FAILED || sem == NULL ) { perror(ERROR_PREFIX "sem_open: sem"); return -1; } sem_1 = sem_open(semname_1, 0); if( sem_1 == SEM_FAILED || sem_1 == NULL ) { perror(ERROR_PREFIX "sem_open: sem_1"); return -1; } sem_wait(sem_1); fprintf(stderr, "child %d try to get lock, prio: %d\n", id, get_my_prio()); if (sem_wait(sem) == -1) { perror("Error at sem_wait"); fprintf(stderr, "Child %d: Cannot get lock", id); exit(-1); } fprintf(stderr, "child %d got lock\n", id); exit(0); } int main() { #ifndef _POSIX_PRIORITY_SCHEDULING printf("_POSIX_PRIORITY_SCHEDULING not defined\n"); return PTS_UNTESTED; #endif sem_t *sem, *sem_1; int val = 3; /* for sem_1 to track the child state */ int priority; pid_t c_1, c_2, c_3, ret_pid; int retval = PTS_UNRESOLVED; int status; snprintf(semname, 20, "/" TEST "_%d", getpid()); /* Initial value of Semaphore is 1 */ sem = sem_open(semname, O_CREAT, 0777, 1); if( sem == SEM_FAILED || sem == NULL ) { perror(ERROR_PREFIX "sem_open"); return PTS_UNRESOLVED; } snprintf(semname_1, 20, "/" TEST "_%d_1", getpid()); sem_1 = sem_open(semname_1, O_CREAT, 0777, val); if( sem_1 == SEM_FAILED || sem_1 == NULL ) { perror(ERROR_PREFIX "sem_open: sem_1"); sem_unlink(semname); return PTS_UNRESOLVED; } /* The parent has highest priority */ priority = sched_get_priority_min(SCHED_FIFO) + 3; if (set_my_prio(priority) == -1) { retval = PTS_UNRESOLVED; goto clean_up; } /* Lock Semaphore */ if( sem_wait(sem) == -1 ) { perror(ERROR_PREFIX "sem_wait"); retval = PTS_UNRESOLVED; goto clean_up; } c_1 = fork(); if (c_1 == 0) { /* Child 1, should block */ child_fn(priority - 2, 1); } else if (c_1 < 0) { perror("Error at fork"); retval = PTS_UNRESOLVED; goto clean_up; } fprintf(stderr, "P: child_1:%d forked\n", c_1); sleep(1); c_2 = fork(); if (c_2 == 0) { /* Child 2 */ child_fn(priority - 1, 2); } else if (c_2 < 0) { perror("Error at fork"); retval = PTS_UNRESOLVED; goto clean_up; } fprintf(stderr, "P: child_2: %d forked\n", c_2); /* Make sure the two children has been waiting */ /*do { sleep(1); sem_getvalue(sem_1, &val); //printf("val = %d\n", val); } while (val != 1); */ c_3 = fork(); if (c_3 == 0) { /* Child 3 */ child_fn(priority - 1, 3); } fprintf(stderr, "P: child_3: %d forked\n", c_3); /* Make sure child 3 has been waiting for the lock */ /*do { sleep(1); sem_getvalue(sem_1, &val); //printf("val = %d\n", val); } while (val != 0); */ /* Ok, let's release the lock */ fprintf(stderr, "P: release lock\n"); sem_post(sem); ret_pid = wait(&status); if (ret_pid == c_2 && WIFEXITED(status) && WEXITSTATUS(status) == 0) { fprintf(stderr, "P: release lock\n"); sem_post(sem); ret_pid = wait(&status); if (ret_pid == c_3 && WIFEXITED(status) && WEXITSTATUS(status) == 0) { fprintf(stderr, "P: release lock\n"); sem_post(sem); ret_pid = wait(&status); if (ret_pid == c_1 && WIFEXITED(status) && WEXITSTATUS(status) == 0) { printf("Test Pass\n"); retval = PTS_PASS; goto clean_up; } printf("Test Fail: Expect child_1: %d, got %d\n", c_1, ret_pid); retval = PTS_FAIL; goto clean_up; } else { printf("Test Fail: Expect child_3: %d, got %d\n", c_3, ret_pid); retval = PTS_FAIL; sem_post(sem); while((wait(NULL) > 0)); goto clean_up; } } else { printf("Test Fail: Expect child_2: %d, got %d\n", c_2, ret_pid); retval = PTS_FAIL; sem_post(sem); sem_post(sem); while((wait(NULL) > 0)); goto clean_up; } clean_up: sem_close(sem); sem_close(sem_1); sem_unlink(semname); sem_unlink(semname_1); return retval; }