| /* |
| * 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 process-shared attribute shall be set to PTHREAD_PROCESS_SHARED |
| * to permit a read-write lock to be operated upon by any thread |
| * that has access to the memory where the read-write lock is allocated, |
| * even if the read-write lock is allocated in memory that is shared by |
| * multiple processes. |
| * |
| * steps: |
| * 1. Create a piece of shared memory object, create a read write lock 'rwlock' and |
| * set the PTHREAD_PROCESS_SHARED attribute. |
| * 2. Parent map the shared memory to its memory space, put 'rwlock' into it; |
| * 3. Parent get read lock; |
| * 4. Fork to create child, parent wait until child call pthread_rwlock_wrlock() |
| * 5. Child map the shared memory to its memory space; |
| * 6. Child call pthread_rwlock_trywrlock(), should fail with EBUSY; |
| * 7. Child call pthread_rwlock_wrlock(), should block; |
| * 8. Parent unlock 'rwlock' |
| * 9. Child should get the write lock. |
| */ |
| |
| #include <sys/mman.h> |
| #include <sys/stat.h> |
| #include <sys/wait.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <pthread.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include "posixtest.h" |
| |
| struct shmstruct { |
| pthread_rwlock_t rwl; |
| int data; |
| } *rwlock_data; |
| |
| int main(void) |
| { |
| |
| /* 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 |
| |
| pthread_rwlockattr_t rwla; |
| int pshared = PTHREAD_PROCESS_SHARED; |
| |
| char shm_name[] = "tmp_pthread_rwlock_getpshared"; |
| int shm_fd; |
| int pid; |
| |
| /* Initialize a rwlock attributes object */ |
| if (pthread_rwlockattr_init(&rwla) != 0) { |
| printf("Error at pthread_rwlockattr_init()\n"); |
| return PTS_UNRESOLVED; |
| } |
| |
| if (pthread_rwlockattr_setpshared(&rwla, pshared) != 0) { |
| printf("Error at pthread_rwlockattr_setpshared()\n"); |
| return PTS_UNRESOLVED; |
| } |
| |
| if (pthread_rwlockattr_getpshared(&rwla, &pshared) != 0) { |
| printf |
| ("Test FAILED: Error at pthread_rwlockattr_getpshared()\n"); |
| return PTS_FAIL; |
| } |
| |
| if (pshared != PTHREAD_PROCESS_SHARED) { |
| printf("Test FAILED: Got error shared attribute 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(struct shmstruct)) != 0) { |
| perror("Error at ftruncate()"); |
| shm_unlink(shm_name); |
| return PTS_UNRESOLVED; |
| } |
| |
| /* Map the shared memory object to my memory */ |
| rwlock_data = |
| mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE, |
| MAP_SHARED, shm_fd, 0); |
| |
| if (rwlock_data == MAP_FAILED) { |
| perror("Error at first mmap()"); |
| shm_unlink(shm_name); |
| return PTS_UNRESOLVED; |
| } |
| |
| if ((pthread_rwlock_init(&(rwlock_data->rwl), &rwla)) != 0) { |
| printf("Error at pthread_rwlock_init()\n"); |
| return PTS_UNRESOLVED; |
| } |
| |
| if ((pthread_rwlockattr_destroy(&rwla)) != 0) { |
| printf("Error at pthread_rwlockattr_destroy()\n"); |
| return PTS_UNRESOLVED; |
| } |
| |
| printf("Parent getting read lock.\n"); |
| if ((pthread_rwlock_rdlock(&(rwlock_data->rwl))) != 0) { |
| printf("Error at pthread_rwlock_rdlock()\n"); |
| return PTS_UNRESOLVED; |
| } |
| printf("Parent got read lock.\n"); |
| rwlock_data->data = 0; |
| |
| pid = fork(); |
| if (pid == -1) { |
| perror("Error at fork()"); |
| return PTS_UNRESOLVED; |
| } else if (pid > 0) { |
| /* Parent */ |
| /* wait until child do wrlock */ |
| while (rwlock_data->data == 0) { |
| sleep(1); |
| } |
| |
| printf("Parent unlocking.\n"); |
| if (pthread_rwlock_unlock(&(rwlock_data->rwl)) != 0) { |
| printf("Parent: error at pthread_rwlock_unlock()\n"); |
| return PTS_FAIL; |
| } |
| printf("Parent unlocked.\n"); |
| |
| /* Wait for child to end */ |
| wait(NULL); |
| |
| if ((shm_unlink(shm_name)) != 0) { |
| perror("Error at shm_unlink()"); |
| return PTS_UNRESOLVED; |
| } |
| |
| if (rwlock_data->data == -1) { |
| printf |
| ("Test FAILED: child did not block on write lock\n"); |
| return PTS_FAIL; |
| } |
| |
| printf("Test PASSED\n"); |
| return PTS_PASS; |
| } else { |
| /* Child */ |
| /* Map the shared object to child's memory */ |
| rwlock_data = |
| mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE, |
| MAP_SHARED, shm_fd, 0); |
| |
| if (rwlock_data == MAP_FAILED) { |
| perror("Error at first mmap()"); |
| return PTS_UNRESOLVED; |
| } |
| |
| printf("Child tries to get write lock, should get EBUSY.\n"); |
| if ((pthread_rwlock_trywrlock(&(rwlock_data->rwl))) != EBUSY) { |
| printf("Test FAILED: Child expects EBUSY\n"); |
| return PTS_FAIL; |
| } |
| printf("Child got EBUSY.\n"); |
| |
| printf("Child do wrlock.\n"); |
| |
| /* Tell parent it can unlock now */ |
| rwlock_data->data = 1; |
| |
| /* Should block until parent unlock */ |
| if ((pthread_rwlock_wrlock(&(rwlock_data->rwl))) != 0) { |
| printf("Child:pthread_rwlock_wrlock() error\n"); |
| printf |
| ("Test FAILED: Error while write lock the shared rwlock\n"); |
| rwlock_data->data = -1; |
| return PTS_FAIL; |
| } |
| printf("Child got wrlock.\n"); |
| if ((pthread_rwlock_unlock(&(rwlock_data->rwl))) != 0) { |
| printf("Child:pthread_rwlock_unlock() error\n"); |
| printf("Error while write unlock the shared rwlock\n"); |
| rwlock_data->data = -1; |
| return PTS_FAIL; |
| } |
| } |
| } |