/* * Copyright (c) 2002, 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. * * The idea of this case comes from GNU C library NPTL test tst-barrier2.c. * * The process-shared attribute is set to PTHREAD_PROCESS_SHARED to permit * a barrier to be operated upon by any thread that has access to the memory * where the barrier is allocated. If the process-shared attribute * is PTHREAD_PROCESS_PRIVATE, the barrier shall only be operated * upon by threads created within the same process as the thread * that initialized the barrier; if threads of different processes attempt * to operate on such a barrier, the behavior is undefined. * The default value of the attribute shall be PTHREAD_PROCESS_PRIVATE. Both constants * PTHREAD_PROCESS_SHARED and PTHREAD_PROCESS_PRIVATE are defined in . * * steps: * 1. Create a piece of shared memory object, create pthread barrier object 'barrier' * and set the PTHREAD_PROCESS_SHARED attribute. * 2. Parent map the shared memory to its memory space, put 'barrier' into it; * 3. Parent fork to create child process; * 4. Child process map the 'barrier' to its memory space; * 5. Parent and Child execute same code: loop N times, calling pthread_barrier_wait() * 6. Parent and Child should not block on pthread_barrier_wait() */ #define _XOPEN_SOURCE 600 #include #include #include #include #include #include #include #include #include #include #include "posixtest.h" #define LOOP_NUM 10 void sig_handler() { printf("Interrupted by SIGALRM\n"); printf("Test Fail: block on pthread_barrier_wait()\n"); exit(PTS_FAIL); } int main() { /* Make sure there is process-shared capability. */ #ifndef PTHREAD_PROCESS_SHARED fprintf(stderr,"process-shared attribute is not available for testing\n"); return PTS_UNSUPPORTED; #endif static pthread_barrier_t* barrier; pthread_barrierattr_t ba; int pshared = PTHREAD_PROCESS_SHARED; char shm_name[] = "tmp_pthread_barrierattr_getpshared"; int shm_fd; int pid; int loop; int serial = 0; int rc; int status = 0; struct sigaction act; /* Set up parent to handle SIGALRM */ act.sa_flags = 0; act.sa_handler = sig_handler; sigfillset(&act.sa_mask); sigaction(SIGALRM, &act, 0); /* Initialize a barrier attributes object */ if(pthread_barrierattr_init(&ba) != 0) { printf("Error at pthread_barrierattr_init()\n"); return PTS_UNRESOLVED; } /* Set the pshard value to private to shared */ if(pthread_barrierattr_setpshared(&ba, pshared) != 0) { printf("Error at pthread_barrierattr_setpshared()\n"); return PTS_UNRESOLVED; } if(pthread_barrierattr_getpshared(&ba, &pshared) != 0) { printf("Test FAILED: Error at pthread_barrierattr_getpshared()\n"); return PTS_FAIL; } if(pshared != PTHREAD_PROCESS_SHARED) { printf("Test FAILED: Incorrect pshared value %d\n", pshared); return PTS_FAIL; } /* Create shared object */ shm_unlink(shm_name); shm_fd = shm_open(shm_name, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR); if(shm_fd == -1) { perror("Error at shm_open()"); return PTS_UNRESOLVED; } if(ftruncate(shm_fd, sizeof(pthread_barrier_t)) != 0) { perror("Error at ftruncate()"); shm_unlink(shm_name); return PTS_UNRESOLVED; } /* Map the shared memory object to my memory */ barrier = mmap(NULL, sizeof(pthread_barrier_t), PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0); if(barrier == MAP_FAILED) { perror("Error at first mmap()"); shm_unlink(shm_name); return PTS_UNRESOLVED; } /* Initialize a barrier */ if((pthread_barrier_init(barrier, &ba, 2)) != 0) { printf("Error at pthread_barrier_init()\n"); return PTS_UNRESOLVED; } /* Cleanup */ if((pthread_barrierattr_destroy(&ba)) != 0) { printf("Error at pthread_barrierattr_destroy()\n"); return PTS_UNRESOLVED; } /* Fork a child process */ pid = fork(); if(pid == -1) { perror("Error at fork()"); return PTS_UNRESOLVED; } else if(pid == 0) { /* Child */ /* Map the shared object to child's memory */ barrier = mmap(NULL, sizeof(pthread_barrier_t), PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0); if(barrier == MAP_FAILED) { perror("child: Error at first mmap()"); return PTS_UNRESOLVED; } } else { printf("parent pid : %d, child pid : %d\n", getpid(), pid); printf("parent: send me SIGALRM 2 secs later in case I am blocked\n"); alarm(2); } for(loop = 0; loop < LOOP_NUM; loop++) { rc = pthread_barrier_wait(barrier); if(rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) { printf("Test FAILED: %d: pthread_barrier_wait() got unexpected " "return code : %d\n" , getpid(), rc); exit(PTS_FAIL); } else if(rc == PTHREAD_BARRIER_SERIAL_THREAD) { serial++; printf("process %d: get PTHREAD_BARRIER_SERIAL_THREAD\n" , getpid()); } } if(pid > 0) { /* parent */ if( wait(&status) != pid) { printf("parent: error at waitpid()\n"); return PTS_UNRESOLVED; } if(!WIFEXITED(status)) { printf("Child exited abnormally\n"); return PTS_UNRESOLVED; } if((WEXITSTATUS(status) + serial) != LOOP_NUM) { printf("status = %d\n", status); printf("serial = %d\n", serial); printf("Test FAILED: One of the two processes should get " "PTHREAD_BARRIER_SERIAL_THREAD\n"); return PTS_FAIL; } /* Cleanup */ if(pthread_barrier_destroy(barrier) != 0) { printf("Error at pthread_barrier_destroy()"); return PTS_UNRESOLVED; } if((shm_unlink(shm_name)) != 0) { perror("Error at shm_unlink()"); return PTS_UNRESOLVED; } printf("Test PASSED\n"); return PTS_PASS; } if(pid == 0) { exit(serial); } }