msg_send.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #define _GNU_SOURCE
  2. #include <stdalign.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <sys/ipc.h>
  7. #include <sys/msg.h>
  8. #include <sys/time.h>
  9. #include <sys/types.h>
  10. #include <sys/wait.h>
  11. #include <unistd.h>
  12. #define PAYLOAD_SIZE 10
  13. #define TEST_TIMES 1000
  14. #define TEST_TYPES 2
  15. #define DO_BENCH 1
  16. enum { PARALLEL, SERIAL, IN_PROCESS } mode = PARALLEL;
  17. int pipefds[4], key;
  18. /* server always sends messages */
  19. void server(void) {
  20. struct timeval tv1, tv2;
  21. int msqid;
  22. alignas(struct msgbuf) char _data[sizeof(struct msgbuf) + PAYLOAD_SIZE];
  23. struct msgbuf* buf = (struct msgbuf*)_data;
  24. if ((msqid = msgget(key, mode == SERIAL ? 0600 | IPC_CREAT : 0)) < 0) {
  25. perror("msgget");
  26. exit(1);
  27. }
  28. gettimeofday(&tv1, NULL);
  29. for (int i = 0; i < TEST_TIMES; i++) {
  30. buf->mtype = (i % TEST_TYPES) + 1;
  31. if (msgsnd(msqid, buf, PAYLOAD_SIZE, 0) < 0) {
  32. perror("msgsnd");
  33. exit(1);
  34. }
  35. #ifndef DO_BENCH
  36. printf("Message: \"%s\" sent\n", buf->mtext);
  37. #endif
  38. }
  39. gettimeofday(&tv2, NULL);
  40. if (mode == PARALLEL) {
  41. char byte = 0;
  42. close(pipefds[0]);
  43. if (write(pipefds[1], &byte, 1) != 1) {
  44. perror("write error");
  45. exit(1);
  46. }
  47. close(pipefds[3]);
  48. if (read(pipefds[2], &byte, 1) != 1) {
  49. perror("read error");
  50. exit(1);
  51. }
  52. }
  53. printf("time spent on %d msgsnd: %llu microsecond\n", TEST_TIMES,
  54. (tv2.tv_sec * 1000000ull + tv2.tv_usec) - (tv1.tv_sec * 1000000ull + tv1.tv_usec));
  55. if (mode != IN_PROCESS)
  56. exit(0);
  57. }
  58. /* client always sends messages */
  59. void client(void) {
  60. struct timeval tv1, tv2;
  61. int msqid;
  62. alignas(struct msgbuf) char _data[sizeof(struct msgbuf) + PAYLOAD_SIZE];
  63. struct msgbuf* buf = (struct msgbuf*)_data;
  64. int ret;
  65. if (mode == PARALLEL) {
  66. char byte = 0;
  67. close(pipefds[1]);
  68. if (read(pipefds[0], &byte, 1) != 1) {
  69. perror("read error");
  70. exit(1);
  71. }
  72. }
  73. if ((msqid = msgget(key, 0)) < 0) {
  74. perror("msgget");
  75. exit(1);
  76. }
  77. gettimeofday(&tv1, NULL);
  78. for (int i = 0; i < TEST_TIMES; i++) {
  79. int type = (i % TEST_TYPES) + 1;
  80. if ((ret = msgrcv(msqid, buf, PAYLOAD_SIZE, type, 0)) < 0) {
  81. perror("msgrcv");
  82. exit(1);
  83. }
  84. #ifndef DO_BENCH
  85. buf->mtext[ret] = 0;
  86. printf("Client received: \"%s\"\n", buf->mtext);
  87. #endif
  88. }
  89. gettimeofday(&tv2, NULL);
  90. if (mode == PARALLEL) {
  91. char byte = 0;
  92. close(pipefds[2]);
  93. if (write(pipefds[3], &byte, 1) != 1) {
  94. perror("write error");
  95. exit(1);
  96. }
  97. }
  98. printf("time spent on %d msgrcv: %llu microsecond\n", TEST_TIMES,
  99. (tv2.tv_sec * 1000000ull + tv2.tv_usec) - (tv1.tv_sec * 1000000ull + tv1.tv_usec));
  100. if (mode != IN_PROCESS)
  101. exit(0);
  102. }
  103. int main(int argc, char** argv) {
  104. int msqid;
  105. key = rand();
  106. #ifndef DO_BENCH
  107. printf("Msg queue key: 0x%8x\n", key);
  108. #endif
  109. /* server run first and client run later */
  110. if (argc == 2 && strcmp(argv[1], "serial") == 0) {
  111. mode = SERIAL;
  112. if (fork() == 0)
  113. server();
  114. wait(NULL);
  115. if (fork() == 0)
  116. client();
  117. wait(NULL);
  118. return 0;
  119. }
  120. if ((msqid = msgget(key, 0600 | IPC_CREAT)) < 0) {
  121. perror("msgget");
  122. exit(1);
  123. }
  124. /* server run first and client run later (in the same process) */
  125. if (argc == 2 && strcmp(argv[1], "in-process") == 0) {
  126. mode = IN_PROCESS;
  127. server();
  128. client();
  129. msgctl(msqid, IPC_RMID, NULL);
  130. return 0;
  131. }
  132. if (pipe(&pipefds[0]) < 0 || pipe(&pipefds[2]) < 0) {
  133. perror("pipe error");
  134. return 1;
  135. }
  136. /* server to be the parent and client to be the child */
  137. if (argc == 1) {
  138. if (fork() == 0)
  139. client();
  140. else
  141. server();
  142. }
  143. /* client to be the parent and server to be the child */
  144. if (argc == 2 && strcmp(argv[1], "reverse") == 0) {
  145. if (fork() == 0)
  146. server();
  147. else
  148. client();
  149. }
  150. /* both client and server are children */
  151. if (argc == 2 && strcmp(argv[1], "children") == 0) {
  152. if (fork() == 0)
  153. server();
  154. if (fork() == 0)
  155. client();
  156. wait(NULL);
  157. wait(NULL);
  158. }
  159. msgctl(msqid, IPC_RMID, NULL);
  160. return 0;
  161. }