1/* 2 * Copyright (c) 2002, Intel Corporation. All rights reserved. 3 * Created by: geoffrey.r.gustafson REMOVE-THIS AT intel DOT com 4 * This file is licensed under the GPL license. For the full content 5 * of this license, see the COPYING file at the top level of this 6 * source tree. 7 */ 8 9/* 10 mq_close test plan: 11 1. Create pipes to communicate with child process 12 2. Fork, child waits for command on pipe 13 3. Create and open message queue, set up notification, sends command 14 4. Child opens message queue and tries to set up notification, sends command 15 5. Parent closes the queue, sends command 16 6. Child tries again to set up notification (should succeed verifying that 17 the close successfully removed notify association), sends command 18 7. Parent reports result 19*/ 20 21#include <signal.h> 22#include <stdio.h> 23#include <mqueue.h> 24#include <sys/types.h> 25#include <unistd.h> 26#include <fcntl.h> 27#include <sys/stat.h> 28#include <errno.h> 29#include "posixtest.h" 30 31#define TEST "2-1" 32#define FUNCTION "mq_close" 33#define ERROR_PREFIX "unexpected error: " FUNCTION " " TEST ": " 34 35#define PIPE_READ 0 36#define PIPE_WRITE 1 37 38int parent_process(char *qname, int read_pipe, int write_pipe, int child_pid); 39int child_process(char *qname, int read_pipe, int write_pipe); 40mqd_t open_queue(char *qname, int oflag, int mode); 41int send_receive(int read_pipe, int write_pipe, char send, char *reply); 42 43int main() 44{ 45 char qname[50]; 46 pid_t pid; 47 int rval; 48 int to_parent[2]; 49 int to_child[2]; 50 struct sigaction sa; 51 52 sprintf(qname, "/" FUNCTION "_" TEST "_%d", getpid()); 53 54 rval = pipe(to_parent); 55 if (rval == -1) { 56 perror(ERROR_PREFIX "pipe (1)"); 57 return PTS_UNRESOLVED; 58 } 59 60 rval = pipe(to_child); 61 if (rval == -1) { 62 perror(ERROR_PREFIX "pipe (2)"); 63 return PTS_UNRESOLVED; 64 } 65 66 sa.sa_handler = SIG_IGN; 67 sa.sa_flags = 0; 68 sigemptyset(&sa.sa_mask); 69 sigaction(SIGCHLD, &sa, NULL); 70 71 pid = fork(); 72 if (pid == -1) { 73 perror(ERROR_PREFIX "fork"); 74 return PTS_UNRESOLVED; 75 } 76 if (pid == 0) { 77 // child process 78 close(to_parent[PIPE_READ]); 79 close(to_child[PIPE_WRITE]); 80 81 return child_process(qname, to_child[PIPE_READ], 82 to_parent[PIPE_WRITE]); 83 } else { 84 // parent process 85 close(to_parent[PIPE_WRITE]); 86 close(to_child[PIPE_READ]); 87 88 return parent_process(qname, to_parent[PIPE_READ], 89 to_child[PIPE_WRITE], pid); 90 } 91 92 return PTS_UNRESOLVED; 93} 94 95int parent_process(char *qname, int read_pipe, int write_pipe, int child_pid) 96{ 97 mqd_t queue; 98 struct sigevent se; 99 int rval; 100 char reply; 101 102 queue = open_queue(qname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); 103 if (queue == (mqd_t)-1) { 104 return PTS_UNRESOLVED; 105 } 106 107 se.sigev_notify = SIGEV_SIGNAL; 108 se.sigev_signo = SIGUSR1; 109 110 if (mq_notify(queue, &se)) { 111 perror(ERROR_PREFIX "mq_notify (1)"); 112 mq_close(queue); 113 mq_unlink(qname); 114 return PTS_UNRESOLVED; 115 } 116 117 // send 'a' - signal child to verify it can't call notify 118 rval = send_receive(read_pipe, write_pipe, 'a', &reply); 119 if (rval) { 120 mq_close(queue); 121 mq_unlink(qname); 122 return rval; 123 } 124 125 if (reply != 'b') { 126 puts(ERROR_PREFIX "send_receive: " 127 "expected a 'b'"); 128 mq_close(queue); 129 mq_unlink(qname); 130 return PTS_UNRESOLVED; 131 } 132 133 // close the queue to perform test 134 rval = mq_close(queue); 135 mq_unlink(qname); 136 if (rval) { 137 perror(ERROR_PREFIX "mq_close:"); 138 return PTS_UNRESOLVED; 139 } 140 // send 'c' - signal child to verify it can call notify 141 rval = send_receive(read_pipe, write_pipe, 'c', &reply); 142 if (rval) { 143 return rval; 144 } 145 146 if (reply == 'd') { 147 puts("Test PASSED"); 148 return PTS_PASS; 149 } else if (reply == 'e') { 150 puts("Test FAILED"); 151 return PTS_FAIL; 152 } else { 153 puts(ERROR_PREFIX "bad reply from child"); 154 return PTS_UNRESOLVED; 155 } 156} 157 158int child_process(char *qname, int read_pipe, int write_pipe) 159{ 160 mqd_t queue; 161 struct sigevent se; 162 char reply; 163 int rval; 164 165 // wait for 'a' signal from parent 166 rval = send_receive(read_pipe, write_pipe, 0, &reply); 167 if (rval) { 168 return rval; 169 } 170 171 if (reply != 'a') { 172 puts(ERROR_PREFIX "send_receive: " 173 "expected an 'a'"); 174 return PTS_UNRESOLVED; 175 } 176 177 // open the queue and attempt to set up notification 178 queue = open_queue(qname, O_RDWR, 0); 179 if (queue == (mqd_t)-1) { 180 return PTS_UNRESOLVED; 181 } 182 183 // try notify while parent still has queue open - should fail 184 se.sigev_notify = SIGEV_SIGNAL; 185 if (!mq_notify(queue, &se)) { 186 puts(ERROR_PREFIX "mq_notify (2): " 187 "should have failed"); 188 return PTS_UNRESOLVED; 189 } 190 191 // send 'b' - signal parent to close queue 192 rval = send_receive(read_pipe, write_pipe, 'b', &reply); 193 if (rval) { 194 return rval; 195 } 196 197 if (reply != 'c') { 198 puts(ERROR_PREFIX "send_receive: " 199 "expected a 'c'"); 200 return PTS_UNRESOLVED; 201 } 202 203 // try notify after parent closed queue - should succeed 204 se.sigev_notify = SIGEV_SIGNAL; 205 se.sigev_signo = 0; 206 rval = mq_notify(queue, &se); 207 208 // send 'd' for success and 'e' for failure 209 send_receive(read_pipe, write_pipe, rval ? 'e':'d', NULL); 210 211 return 0; 212} 213 214mqd_t open_queue(char *qname, int oflag, int mode) { 215 mqd_t queue; 216 217 queue = mq_open(qname, oflag, mode, NULL); 218 if (queue == (mqd_t)-1) { 219 perror(ERROR_PREFIX "mq_open"); 220 } 221 222 return queue; 223} 224 225int send_receive(int read_pipe, int write_pipe, char send, char *reply) { 226 ssize_t bytes; 227 228 if (send) { 229 bytes = write(write_pipe, &send, 1); 230 if (bytes == -1) { 231 perror(ERROR_PREFIX "write (1)"); 232 return PTS_UNRESOLVED; 233 } 234 } 235 236 if (reply) { 237 bytes = read(read_pipe, reply, 1); 238 if (bytes == -1) { 239 perror(ERROR_PREFIX "read"); 240 return PTS_UNRESOLVED; 241 } else if (bytes == 0) { 242 puts(ERROR_PREFIX "read: EOF"); 243 return PTS_UNRESOLVED; 244 } 245 } 246 247 return 0; 248} 249