| /* |
| * 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 <pthread.h>. |
| * |
| * 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 <pthread.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <sys/mman.h> |
| #include <fcntl.h> |
| #include <sys/wait.h> |
| #include <sys/stat.h> |
| #include <signal.h> |
| #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); |
| } |
| |
| } |