1/* 2 * Copyright (c) 2004, 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 * adam.li@intel.com - 2004-04-29 7 */ 8 9/* 10 * Test that if the message queue is full and O_NONBLOCK is not set, 11 * mq_timedsend() will block until abs_timeout is reached. 12 * 13 * Test by sending messages in a child process until the message queue is full. 14 * At this point, the child should be blocking on sending. Then, have the 15 * parent wait for the timeout and return pass when the next message is sent 16 * to the message queue. 17 * 18 * If Timers is supported, then abs_timeout is based on CLOCK_REALTIME. 19 * Otherwise, the timeout is based on the system clock (time() function). 20 */ 21 22#include <stdio.h> 23#include <mqueue.h> 24#include <fcntl.h> 25#include <sys/stat.h> 26#include <sys/types.h> 27#include <sys/wait.h> 28#include <time.h> 29#include <unistd.h> 30#include <string.h> 31#include <stdlib.h> 32#include <stdint.h> 33#include <signal.h> 34#include <errno.h> 35#include "posixtest.h" 36 37#define NAMESIZE 50 38#define MSGSTR "0123456789" 39#define BUFFER 40 40#define MAXMSG 5 41 42#define TIMEOUT 7 43 44#define CHILDPASS 1 45#define CHILDFAIL 0 46 47char gqname[NAMESIZE]; 48mqd_t gqueue; 49 50/* 51 * This handler is just used to catch the signal and stop sleep (so the 52 * parent knows the child is still busy sending signals). 53 */ 54void stopsleep_handler(int signo) 55{ 56 return; 57} 58 59int main() 60{ 61 int pid; 62 struct mq_attr attr; 63 const char *msgptr = MSGSTR; 64 65 sprintf(gqname, "/mq_timedsend_16-1_%d", getpid()); 66 67 attr.mq_maxmsg = MAXMSG; 68 attr.mq_msgsize = BUFFER; 69 gqueue = mq_open(gqname, O_CREAT |O_RDWR, S_IRUSR | S_IWUSR, &attr); 70 mq_unlink(gqname); 71 if (gqueue == (mqd_t)-1) { 72 perror("mq_open() did not return success"); 73 return PTS_UNRESOLVED; 74 } 75 76 if ((pid = fork()) == 0) { 77 /* child here */ 78 int i, sig; 79 struct timespec ts; 80 sigset_t mask; 81 82 /* wait for parent to set up handler */ 83 sigemptyset(&mask); 84 sigaddset(&mask, SIGUSR1); 85 sigprocmask(SIG_BLOCK,&mask,NULL); 86 sigwait(&mask, &sig); 87 88 /* child should block in < TIMEOUT seconds */ 89#ifdef _POSIX_TIMERS 90 printf("Using CLOCK_REALTIME\n"); 91 clock_gettime(CLOCK_REALTIME, &ts); 92 ts.tv_sec += TIMEOUT; 93#else 94 ts.tv_sec=time(NULL)+TIMEOUT; 95#endif 96 ts.tv_nsec=0; 97 98 for (i=0; i<MAXMSG+1; i++) { 99 if (mq_timedsend(gqueue, msgptr, 100 strlen(msgptr), 1, &ts) != 0) { 101 /* send will fail after timeout occurs*/ 102 kill(getppid(), SIGABRT); 103 return CHILDPASS; 104 } 105 /* send signal to parent each time message is sent */ 106 kill(getppid(), SIGABRT); 107 } 108 printf("Child never interrupted\n"); 109 return CHILDFAIL; 110 } else { 111 /* parent here */ 112 struct sigaction act; 113 int j; 114 115 /* parent runs stopsleep_handler when sleep is interrupted 116 by child */ 117 act.sa_handler=stopsleep_handler; 118 act.sa_flags=0; 119 sigemptyset(&act.sa_mask); 120 sigaction(SIGABRT, &act, 0); 121 122 /* wait 1 second and tell child handler is set up */ 123 struct timespec ts; 124 ts.tv_sec = 1; 125 ts.tv_nsec = 0; 126 nanosleep(&ts, NULL); 127 kill(pid, SIGUSR1); 128 129 /* wait for heartbeats from child */ 130 for (j=0; j<MAXMSG+1; j++) { 131 ts.tv_sec = 3; 132 ts.tv_nsec = 0; 133 if (nanosleep(&ts, NULL) 134 == 0) 135 { 136 /* If sleep finished, child is probably blocking */ 137 break; 138 } 139 } 140 141 if (j == MAXMSG+1) { 142 printf("Child never blocked\n"); 143 printf("Test FAILED\n"); 144 kill(pid, SIGKILL); //kill child 145 mq_close(gqueue); 146 mq_unlink(gqname); 147 return PTS_FAIL; 148 } 149 150 /* 151 * Wait for timeout to complete. 152 */ 153 ts.tv_sec = TIMEOUT; 154 ts.tv_nsec = 0; 155 if (nanosleep(&ts, NULL) == 0) { 156 /* 157 * If sleep lasted the full time, child never timed out 158 */ 159 printf("Child never timed out\n"); 160 kill(pid, SIGKILL); //kill child 161 mq_close(gqueue); 162 mq_unlink(gqname); 163 printf("Test FAILED\n"); 164 return PTS_FAIL; 165 } 166 167 mq_close(gqueue); 168 mq_unlink(gqname); 169 printf("Test PASSED\n"); 170 return PTS_PASS; 171 } 172 173 return PTS_UNRESOLVED; 174} 175 176