1 /* 2 * Copyright (c) 2002, Intel Corporation. All rights reserved. 3 * This file is licensed under the GPL license. For the full content 4 * of this license, see the COPYING file at the top level of this 5 * source tree. 6 * 7 * Test pthread_spin_init(pthread_spinlock_t *lock, int pshared) 8 * 9 * If the Thread Process-Shared Synchronization option is supported and 10 * the value of pshared is PTHREAD_PROCESS_SHARED, the implementation shall 11 * permit the spin lock to be opreated upon by any thread that has access 12 * to the memory where the spin lock is allocated, even if it is allocated 13 * in memory that is shared by multiple processes. 14 * 15 * steps: 16 * 1. Create a piece of shared memory object, create a spin lock 'spinlock' and 17 * set the PTHREAD_PROCESS_SHARED attribute. 18 * 2. Parent map the shared memory to its memory space, put 'spinlock' into it; 19 * 3. Parent get the spin lock; 20 * 4. Fork to create child 21 * 5. Child map the shared memory to its memory space; 22 * 6. Child call pthread_spin_trylock(), should fail with EBUSY 23 */ 24 25 #include <sys/mman.h> 26 #include <sys/stat.h> 27 #include <sys/wait.h> 28 #include <errno.h> 29 #include <fcntl.h> 30 #include <pthread.h> 31 #include <stdio.h> 32 #include <unistd.h> 33 #include "posixtest.h" 34 35 struct shmstruct { 36 pthread_spinlock_t spinlock; 37 int data; 38 } *spinlock_data; 39 40 int main(void) 41 { 42 43 /* Make sure there is process-shared capability. */ 44 #ifndef PTHREAD_PROCESS_SHARED 45 fprintf(stderr, 46 "process-shared attribute is not available for testing\n"); 47 return PTS_UNSUPPORTED; 48 #endif 49 50 int pshared = PTHREAD_PROCESS_SHARED; 51 52 char shm_name[] = "tmp_pthread_spinlock_getpshared"; 53 int shm_fd; 54 int pid; 55 56 /* Create shared object */ 57 shm_unlink(shm_name); 58 shm_fd = 59 shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); 60 if (shm_fd == -1) { 61 perror("Error at shm_open()"); 62 return PTS_UNRESOLVED; 63 } 64 65 if (ftruncate(shm_fd, sizeof(struct shmstruct)) != 0) { 66 perror("Error at ftruncate()"); 67 shm_unlink(shm_name); 68 return PTS_UNRESOLVED; 69 } 70 71 /* Map the shared memory object to parent's memory */ 72 spinlock_data = 73 mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE, 74 MAP_SHARED, shm_fd, 0); 75 76 if (spinlock_data == MAP_FAILED) { 77 perror("Error at first mmap()"); 78 shm_unlink(shm_name); 79 return PTS_UNRESOLVED; 80 } 81 82 /* Initialize spinlock */ 83 if ((pthread_spin_init(&(spinlock_data->spinlock), pshared)) != 0) { 84 printf("Test FAILED: Error at pthread_rwlock_init()\n"); 85 return PTS_FAIL; 86 } 87 88 printf("main: attempt spin lock\n"); 89 if ((pthread_spin_lock(&(spinlock_data->spinlock))) != 0) { 90 printf("Error at pthread_spin_lock()\n"); 91 return PTS_UNRESOLVED; 92 } 93 printf("main: acquired spin lock\n"); 94 95 /* Initialize spinlock data */ 96 spinlock_data->data = 0; 97 98 /* Fork a child process */ 99 pid = fork(); 100 if (pid == -1) { 101 perror("Error at fork()"); 102 return PTS_UNRESOLVED; 103 } else if (pid > 0) { 104 /* Parent */ 105 /* wait until child writes to spinlock data */ 106 while (spinlock_data->data != 1) 107 sleep(1); 108 109 printf("main: unlock spin lock\n"); 110 if (pthread_spin_unlock(&(spinlock_data->spinlock)) != 0) { 111 printf("Parent: error at pthread_spin_unlock()\n"); 112 return PTS_UNRESOLVED; 113 } 114 115 /* Tell child that parent unlocked the spin lock */ 116 spinlock_data->data = 2; 117 118 /* Wait until child ends */ 119 wait(NULL); 120 121 if ((shm_unlink(shm_name)) != 0) { 122 perror("Error at shm_unlink()"); 123 return PTS_UNRESOLVED; 124 } 125 126 printf("Test PASSED\n"); 127 return PTS_PASS; 128 } else { 129 /* Child */ 130 /* Map the shared object to child's memory */ 131 spinlock_data = 132 mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE, 133 MAP_SHARED, shm_fd, 0); 134 135 if (spinlock_data == MAP_FAILED) { 136 perror("child : Error at mmap()"); 137 return PTS_UNRESOLVED; 138 } 139 140 printf("child: attempt spin lock\n"); 141 if ((pthread_spin_trylock(&(spinlock_data->spinlock))) != EBUSY) { 142 printf("Test FAILED: Child expects EBUSY\n"); 143 return PTS_FAIL; 144 } 145 printf("child: correctly got EBUSY\n"); 146 147 /* Tell parent it can unlock now */ 148 spinlock_data->data = 1; 149 150 /* Wait for parent to unlock spinlock */ 151 while (spinlock_data->data != 2) 152 sleep(1); 153 154 /* Child tries to get spin lock after parent unlock, 155 * it should get the lock. */ 156 printf("child: attempt spin lock\n"); 157 if ((pthread_spin_trylock(&(spinlock_data->spinlock))) != 0) { 158 printf("Test FAILED: Child should get the lock\n"); 159 return PTS_FAIL; 160 } 161 printf("child: acquired spin lock\n"); 162 163 printf("child: unlock spin lock\n"); 164 if (pthread_spin_unlock(&(spinlock_data->spinlock)) != 0) { 165 printf("Child: error at pthread_spin_unlock()\n"); 166 return PTS_UNRESOLVED; 167 } 168 169 if (pthread_spin_destroy(&(spinlock_data->spinlock)) != 0) { 170 printf("Child: error at pthread_spin_destroy()\n"); 171 return PTS_UNRESOLVED; 172 } 173 } 174 } 175