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 38 int parent_process(char *qname, int read_pipe, int write_pipe, int child_pid); 39 int child_process(char *qname, int read_pipe, int write_pipe); 40 mqd_t open_queue(char *qname, int oflag, int mode); 41 int send_receive(int read_pipe, int write_pipe, char send, char *reply); 42 43 int main(void) 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 95 int 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 // send 'a' - signal child to verify it can't call notify 117 rval = send_receive(read_pipe, write_pipe, 'a', &reply); 118 if (rval) { 119 mq_close(queue); 120 mq_unlink(qname); 121 return rval; 122 } 123 124 if (reply != 'b') { 125 puts(ERROR_PREFIX "send_receive: " "expected a 'b'"); 126 mq_close(queue); 127 mq_unlink(qname); 128 return PTS_UNRESOLVED; 129 } 130 // close the queue to perform test 131 rval = mq_close(queue); 132 mq_unlink(qname); 133 if (rval) { 134 perror(ERROR_PREFIX "mq_close:"); 135 return PTS_UNRESOLVED; 136 } 137 // send 'c' - signal child to verify it can call notify 138 rval = send_receive(read_pipe, write_pipe, 'c', &reply); 139 if (rval) { 140 return rval; 141 } 142 143 if (reply == 'd') { 144 puts("Test PASSED"); 145 return PTS_PASS; 146 } else if (reply == 'e') { 147 puts("Test FAILED"); 148 return PTS_FAIL; 149 } else { 150 puts(ERROR_PREFIX "bad reply from child"); 151 return PTS_UNRESOLVED; 152 } 153 } 154 155 int child_process(char *qname, int read_pipe, int write_pipe) 156 { 157 mqd_t queue; 158 struct sigevent se; 159 char reply; 160 int rval; 161 162 // wait for 'a' signal from parent 163 rval = send_receive(read_pipe, write_pipe, 0, &reply); 164 if (rval) { 165 return rval; 166 } 167 168 if (reply != 'a') { 169 puts(ERROR_PREFIX "send_receive: " "expected an 'a'"); 170 return PTS_UNRESOLVED; 171 } 172 // open the queue and attempt to set up notification 173 queue = open_queue(qname, O_RDWR, 0); 174 if (queue == (mqd_t) - 1) { 175 return PTS_UNRESOLVED; 176 } 177 // try notify while parent still has queue open - should fail 178 se.sigev_notify = SIGEV_SIGNAL; 179 if (!mq_notify(queue, &se)) { 180 puts(ERROR_PREFIX "mq_notify (2): " "should have failed"); 181 return PTS_UNRESOLVED; 182 } 183 // send 'b' - signal parent to close queue 184 rval = send_receive(read_pipe, write_pipe, 'b', &reply); 185 if (rval) { 186 return rval; 187 } 188 189 if (reply != 'c') { 190 puts(ERROR_PREFIX "send_receive: " "expected a 'c'"); 191 return PTS_UNRESOLVED; 192 } 193 // try notify after parent closed queue - should succeed 194 se.sigev_notify = SIGEV_SIGNAL; 195 se.sigev_signo = 0; 196 rval = mq_notify(queue, &se); 197 198 // send 'd' for success and 'e' for failure 199 send_receive(read_pipe, write_pipe, rval ? 'e' : 'd', NULL); 200 201 return 0; 202 } 203 204 mqd_t open_queue(char *qname, int oflag, int mode) 205 { 206 mqd_t queue; 207 208 queue = mq_open(qname, oflag, mode, NULL); 209 if (queue == (mqd_t) - 1) { 210 perror(ERROR_PREFIX "mq_open"); 211 } 212 213 return queue; 214 } 215 216 int send_receive(int read_pipe, int write_pipe, char send, char *reply) 217 { 218 ssize_t bytes; 219 220 if (send) { 221 bytes = write(write_pipe, &send, 1); 222 if (bytes == -1) { 223 perror(ERROR_PREFIX "write (1)"); 224 return PTS_UNRESOLVED; 225 } 226 } 227 228 if (reply) { 229 bytes = read(read_pipe, reply, 1); 230 if (bytes == -1) { 231 perror(ERROR_PREFIX "read"); 232 return PTS_UNRESOLVED; 233 } else if (bytes == 0) { 234 puts(ERROR_PREFIX "read: EOF"); 235 return PTS_UNRESOLVED; 236 } 237 } 238 239 return 0; 240 } 241