Home | History | Annotate | Download | only in mq_close
      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