blob: 5b8f8807c391dff31c415468c42b709e9cbd994e [file] [log] [blame]
/*
* 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);
}
}