1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2002 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * FILE : sem02.c 22 * 23 * DESCRIPTION : The application creates several threads using pthread_create(). 24 * One thread performs a semop() with the SEM_UNDO flag set. The change in 25 * sempaphore value performed by that semop should be "undone" only when the 26 * last pthread exits. 27 * 28 * EXPECTED OUTPUT: 29 * Waiter, pid = <pid#> 30 * Poster, pid = <pid#>, posting 31 * Poster posted 32 * Poster exiting 33 * Waiter waiting, pid = <pid#> 34 * Waiter done waiting 35 * 36 * HISTORY: 37 * written by Dave Olien (oliend (at) us.ibm.com) 38 * 03/06/2002 Robbie Williamson (robbiew (at) us.ibm.com) 39 * -ported 40 * 07/04/2003 Paul Larson (plars (at) linuxtestproject.org) 41 * -ported to LTP 42 * 43 */ 44 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <unistd.h> 48 #include <sys/sem.h> 49 #include <errno.h> 50 #include <pthread.h> 51 #include <sys/types.h> 52 #include <sys/ipc.h> 53 #include "lapi/semun.h" 54 #include "test.h" 55 56 #define KEY IPC_PRIVATE 57 58 #define NUMTHREADS 2 59 60 void *retval[NUMTHREADS]; 61 void *waiter(void *); 62 void *poster(void *); 63 void cleanup(void); 64 65 char *TCID = "sem02"; 66 int TST_TOTAL = 1; 67 68 struct sembuf Psembuf = { 0, -1, SEM_UNDO }; 69 struct sembuf Vsembuf = { 0, 1, SEM_UNDO }; 70 71 int sem_id; 72 int err_ret; /* This is used to determine PASS/FAIL status */ 73 int main(int argc, char **argv) 74 { 75 int i, rc; 76 union semun semunion; 77 78 pthread_t pt[NUMTHREADS]; 79 pthread_attr_t attr; 80 81 tst_parse_opts(argc, argv, NULL, NULL); 82 /* Create the semaphore set */ 83 sem_id = semget(KEY, 1, 0666 | IPC_CREAT); 84 if (sem_id < 0) { 85 printf("semget failed, errno = %d\n", errno); 86 exit(1); 87 } 88 /* initialize data structure associated to the semaphore */ 89 semunion.val = 1; 90 semctl(sem_id, 0, SETVAL, semunion); 91 92 /* setup the attributes of the thread */ 93 /* set the scope to be system to make sure the threads compete on a */ 94 /* global scale for cpu */ 95 pthread_attr_init(&attr); 96 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 97 98 err_ret = 1; /* Set initial error value to 1 */ 99 /* Create the threads */ 100 for (i = 0; i < NUMTHREADS; i++) { 101 if (i == 0) 102 rc = pthread_create(&pt[i], &attr, waiter, retval[i]); 103 else 104 rc = pthread_create(&pt[i], &attr, poster, retval[i]); 105 } 106 107 /* Sleep long enough to see that the other threads do what they are supposed to do */ 108 sleep(20); 109 semunion.val = 1; 110 semctl(sem_id, 0, IPC_RMID, semunion); 111 if (err_ret == 1) 112 tst_resm(TFAIL, "failed"); 113 else 114 tst_resm(TPASS, "passed"); 115 cleanup(); 116 117 tst_exit(); 118 } 119 120 /* This thread sleeps 10 seconds then waits on the semaphore. As long 121 as someone has posted on the semaphore, and no undo has taken 122 place, the semop should complete and we'll print "Waiter done 123 waiting." */ 124 void *waiter(void *foo) 125 { 126 int pid; 127 pid = getpid(); 128 129 tst_resm(TINFO, "Waiter, pid = %d", pid); 130 sleep(10); 131 132 tst_resm(TINFO, "Waiter waiting, pid = %d", pid); 133 semop(sem_id, &Psembuf, 1); 134 tst_resm(TINFO, "Waiter done waiting"); 135 err_ret = 0; /* If the message above is displayed, the test is a PASS */ 136 pthread_exit(0); 137 } 138 139 /* This thread immediately posts on the semaphore and then immediately 140 exits. If the *thread* exits, the undo should not happen, and the 141 waiter thread which will start waiting on it in 10 seconds, should 142 still get it. */ 143 void *poster(void *foo) 144 { 145 int pid; 146 147 pid = getpid(); 148 tst_resm(TINFO, "Poster, pid = %d, posting", pid); 149 semop(sem_id, &Vsembuf, 1); 150 tst_resm(TINFO, "Poster posted"); 151 tst_resm(TINFO, "Poster exiting"); 152 153 pthread_exit(0); 154 } 155 156 void cleanup(void) 157 { 158 } 159