00001 /* 00002 IPC timing comparisons 00003 AUP2, Sec. 7.15 00004 00005 Copyright 2003 by Marc J. Rochkind. All rights reserved. 00006 May be copied only for purposes and under conditions described 00007 on the Web page www.basepath.com/aup/copyright.htm. 00008 00009 The Example Files are provided "as is," without any warranty; 00010 without even the implied warranty of merchantability or fitness 00011 for a particular purpose. The author and his publisher are not 00012 responsible for any damages, direct or incidental, resulting 00013 from the use or non-use of these Example Files. 00014 00015 The Example Files may contain defects, and some contain deliberate 00016 coding mistakes that were included for educational reasons. 00017 You are responsible for determining if and how the Example Files 00018 are to be used. 00019 00020 */ 00021 /*[top]*/ 00022 #include "defs.h" 00023 #include "smi_fifo.h" 00024 #include "smi_msg.h" 00025 #include "smi_skt.h" 00026 #include "smi_shm.h" 00027 #include "smi_pshm.h" 00028 #include "smi_mq.h" 00029 #include "../c6/pcsync_sig.h" 00030 #include <sys/wait.h> 00031 #ifdef FREEBSD 00032 #include <netinet/in.h> /* required for arpa/inet.h */ 00033 #endif 00034 #include <arpa/inet.h> 00035 00036 #define NUM_MSGS 500 00037 #define NUM_CLIENTS 4 00038 #define SERVERNAME_LOCAL "MsgTime" 00039 #define SERVERNAME_INET "//localhost:30001" 00040 00041 #define MSG_LEN SMI_MSG_MAX 00042 static int num_msgs = NUM_MSGS; 00043 static int len_msg = 100; 00044 static bool want_check = true; 00045 static bool pcsync = true; 00046 static bool quiet = false; 00047 00048 static bool run_server = true, run_clients = true; 00049 static const char *hostarg = NULL; 00050 00051 typedef enum {MSGCHK_SET, MSGCHK_CALC, MSGCHK_CHK} MSGCHK_OP; 00052 00053 static bool msg_check(void *mbuf, MSGCHK_OP op) 00054 { 00055 struct smi_msg *m = (struct smi_msg *)mbuf; 00056 int n = len_msg / sizeof(long); 00057 long *a = (long *)m->smi_data, sum; 00058 int i; 00059 pid_t pid = getpid(); 00060 00061 if (!want_check) 00062 return true; 00063 switch (op) { 00064 case MSGCHK_SET: 00065 for (i = 1; i < n; i++) 00066 a[i] = htonl(pid + i); 00067 break; 00068 case MSGCHK_CALC: 00069 case MSGCHK_CHK: 00070 sum = 0; 00071 for (i = 1; i < n; i++) 00072 sum += ntohl(a[i]); 00073 if (op == MSGCHK_CALC) 00074 a[0] = htonl(sum); 00075 else if (ntohl(a[0]) != sum) { 00076 errno = 0; 00077 fprintf(stderr, "msg_time: message failed check\n"); 00078 EC_FAIL 00079 } 00080 } 00081 return true; 00082 00083 EC_CLEANUP_BGN 00084 return false; 00085 EC_CLEANUP_END 00086 } 00087 00088 /* 00089 Problem: Server can't just exit when finished, as closing its queue kills semaphores (etc.) that may be needed. 00090 */ 00091 /* 00092 We end up with an opened server in each child, which isn't right, but should not affect timing. Delaying opening the server until the child processes are created would involve making the children wait for the server to start, which involves extra mechanisms. The smi routines typically don't provide for this. 00093 */ 00094 00095 #define time_traffic(method)\ 00096 static bool method##_time(const char *servername)\ 00097 {\ 00098 int i, k;\ 00099 bool bchild = false;\ 00100 pid_t pid_client[NUM_CLIENTS], pid;\ 00101 SMIQ *sqp;\ 00102 struct pcsync pcs;\ 00103 \ 00104 printf("\n" #method "(%s):\n", servername);\ 00105 timestart();\ 00106 if (pcsync)\ 00107 ec_false( pcsync_init(&pcs) )\ 00108 if (run_clients)\ 00109 for (k = 0; k < NUM_CLIENTS; k++)\ 00110 switch (pid_client[k] = fork()) {\ 00111 case -1:\ 00112 syserr("fork 2");\ 00113 case 0:\ 00114 if (pcsync)\ 00115 ec_false( pcsync_wait_for_parent(&pcs) )\ 00116 if (pcsync)\ 00117 (void)pcsync_end(&pcs);\ 00118 if (!quiet)\ 00119 printf("\tProcess %d running freely\n",\ 00120 (int)getpid());\ 00121 bchild = true;\ 00122 ec_null( sqp = smi_open_##method(servername, SMI_CLIENT,\ 00123 len_msg) )\ 00124 for (i = 0; i < num_msgs; i++) {\ 00125 struct smi_msg *msg;\ 00126 ec_false( smi_send_getaddr_##method(sqp, NULL,\ 00127 (void **)&msg) )\ 00128 ec_false( msg_check(msg, MSGCHK_SET) )\ 00129 ec_false( smi_send_release_##method(sqp) )\ 00130 ec_false( smi_receive_getaddr_##method(sqp,\ 00131 (void **)&msg) )\ 00132 ec_false( msg_check(msg, MSGCHK_CHK) )\ 00133 ec_false( smi_receive_release_##method(sqp) )\ 00134 }\ 00135 if (!quiet)\ 00136 printf("\t" #method\ 00137 " client (process %d) exiting normally\n",\ 00138 (int)getpid());\ 00139 ec_false( smi_close_##method(sqp) )\ 00140 exit(EXIT_SUCCESS);\ 00141 }\ 00142 if (pcsync && run_clients && strcmp(#method, "fifo") == 0)\ 00143 ec_false( pcsync_unblock_children(&pcs, NUM_CLIENTS, pid_client) )\ 00144 if (run_server)\ 00145 ec_null( sqp = smi_open_##method(servername, SMI_SERVER,\ 00146 len_msg) )\ 00147 if (pcsync && run_clients && strcmp(#method, "fifo") != 0)\ 00148 ec_false( pcsync_unblock_children(&pcs, NUM_CLIENTS, pid_client) )\ 00149 if (pcsync)\ 00150 (void)pcsync_end(&pcs);\ 00151 if (run_server)\ 00152 for (i = 0; i < NUM_CLIENTS * num_msgs; i++) {\ 00153 struct smi_msg *msg;\ 00154 \ 00155 (void)alarm(200);\ 00156 ec_false( smi_receive_getaddr_##method(sqp, (void **)&msg) )\ 00157 ec_false( msg_check(msg, MSGCHK_CALC) )\ 00158 ec_false( smi_send_getaddr_##method(sqp, &msg->smi_client,\ 00159 (void **)&msg) )\ 00160 ec_false( smi_receive_release_##method(sqp) )\ 00161 ec_false( smi_send_release_##method(sqp) )\ 00162 }\ 00163 if (!quiet)\ 00164 printf("\tServer waiting for client termination...\n");\ 00165 for (k = 0; k < NUM_CLIENTS; k++) {\ 00166 ec_neg1( waitpid(pid_client[k], NULL, 0) )\ 00167 if (!quiet)\ 00168 printf("\tProcess %d terminated.\n", (int)pid);\ 00169 }\ 00170 if (!quiet)\ 00171 printf("\t" #method " server (process %d) exiting normally\n",\ 00172 (int)getpid());\ 00173 if (run_server)\ 00174 ec_false( smi_close_##method(sqp) )\ 00175 timestop(#method);\ 00176 return true;\ 00177 \ 00178 EC_CLEANUP_BGN\ 00179 if (bchild)\ 00180 exit(EXIT_FAILURE);\ 00181 EC_FLUSH(#method " failed")\ 00182 return false;\ 00183 EC_CLEANUP_END\ 00184 } 00185 00186 time_traffic(fifo) 00187 time_traffic(skt) 00188 time_traffic(msg) 00189 time_traffic(mq) 00190 time_traffic(shm) 00191 #if !defined(FREEBSD) && !defined(LINUX) 00192 time_traffic(pshm) 00193 #endif 00194 00195 static void handler(int signum) 00196 { 00197 if (signum == SIGALRM) 00198 (void)write(STDOUT_FILENO, "Alarm Clock -- ignore times\n", 29); 00199 } 00200 00201 int main(int argc, char *argv[]) 00202 { 00203 int c; 00204 struct sigaction act; 00205 00206 memset(&act, 0, sizeof(act)); 00207 act.sa_handler = handler; 00208 ec_neg1( sigaction(SIGALRM, &act, NULL) ) 00209 setbuf(stdout, NULL); 00210 while ((c = getopt(argc, argv, ":ch:stl:xn:qp")) != -1) 00211 switch(c) { 00212 case 'c': 00213 run_clients = false; 00214 break; 00215 case 'h': 00216 hostarg = optarg; 00217 break; 00218 case 'l': 00219 len_msg = atoi(optarg); 00220 break; 00221 case 'n': 00222 num_msgs = atoi(optarg); 00223 break; 00224 case 's': 00225 run_server = false; 00226 break; 00227 case 't': 00228 num_msgs = 100; 00229 break; 00230 case 'q': 00231 quiet = true; 00232 break; 00233 case 'x': 00234 want_check = false; 00235 break; 00236 case 'p': 00237 pcsync = false; 00238 break; 00239 case ':': 00240 fprintf(stderr, "Option -h requires argument.\n"); 00241 /* fall through */ 00242 default: 00243 fprintf(stderr, "Usage: mt [-c] [-s] [-t] [-h host]" 00244 " [-n nummsgs] [-l msglen] [-q] [-p]\n"); 00245 exit(EXIT_FAILURE); 00246 } 00247 00248 #if 1 00249 system("ipcrem >/dev/null 2>/dev/null"); 00250 #else 00251 printf("ipcrem not executed\n"); 00252 #endif 00253 smi_client_nowait = true; 00254 printf("%d messages of %d bytes; %d clients\n", num_msgs, 00255 len_msg, NUM_CLIENTS); 00256 if (hostarg != NULL) 00257 skt_time(hostarg); 00258 else { 00259 fifo_time(SERVERNAME_LOCAL); 00260 skt_time(SERVERNAME_LOCAL); 00261 skt_time(SERVERNAME_INET); 00262 shm_time(SERVERNAME_LOCAL); 00263 msg_time(SERVERNAME_LOCAL); 00264 mq_time(SERVERNAME_LOCAL); 00265 #if !defined(FREEBSD) && !defined(LINUX) 00266 pshm_time(SERVERNAME_LOCAL); 00267 #endif 00268 } 00269 printf("Done\n"); 00270 exit(EXIT_SUCCESS); 00271 00272 EC_CLEANUP_BGN 00273 exit(EXIT_FAILURE); 00274 EC_CLEANUP_END 00275 }