Home | History | Annotate | Download | only in semaphore
      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