trace-agent-rw.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * Read/write thread of a guest agent for virtio-trace
  3. *
  4. * Copyright (C) 2012 Hitachi, Ltd.
  5. * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com>
  6. * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
  7. *
  8. * Licensed under GPL version 2 only.
  9. *
  10. */
  11. #define _GNU_SOURCE
  12. #include <fcntl.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <unistd.h>
  16. #include <sys/syscall.h>
  17. #include "trace-agent.h"
  18. #define READ_WAIT_USEC 100000
  19. void *rw_thread_info_new(void)
  20. {
  21. struct rw_thread_info *rw_ti;
  22. rw_ti = zalloc(sizeof(struct rw_thread_info));
  23. if (rw_ti == NULL) {
  24. pr_err("rw_thread_info zalloc error\n");
  25. exit(EXIT_FAILURE);
  26. }
  27. rw_ti->cpu_num = -1;
  28. rw_ti->in_fd = -1;
  29. rw_ti->out_fd = -1;
  30. rw_ti->read_pipe = -1;
  31. rw_ti->write_pipe = -1;
  32. rw_ti->pipe_size = PIPE_INIT;
  33. return rw_ti;
  34. }
  35. void *rw_thread_init(int cpu, const char *in_path, const char *out_path,
  36. bool stdout_flag, unsigned long pipe_size,
  37. struct rw_thread_info *rw_ti)
  38. {
  39. int data_pipe[2];
  40. rw_ti->cpu_num = cpu;
  41. /* set read(input) fd */
  42. rw_ti->in_fd = open(in_path, O_RDONLY);
  43. if (rw_ti->in_fd == -1) {
  44. pr_err("Could not open in_fd (CPU:%d)\n", cpu);
  45. goto error;
  46. }
  47. /* set write(output) fd */
  48. if (!stdout_flag) {
  49. /* virtio-serial output mode */
  50. rw_ti->out_fd = open(out_path, O_WRONLY);
  51. if (rw_ti->out_fd == -1) {
  52. pr_err("Could not open out_fd (CPU:%d)\n", cpu);
  53. goto error;
  54. }
  55. } else
  56. /* stdout mode */
  57. rw_ti->out_fd = STDOUT_FILENO;
  58. if (pipe2(data_pipe, O_NONBLOCK) < 0) {
  59. pr_err("Could not create pipe in rw-thread(%d)\n", cpu);
  60. goto error;
  61. }
  62. /*
  63. * Size of pipe is 64kB in default based on fs/pipe.c.
  64. * To read/write trace data speedy, pipe size is changed.
  65. */
  66. if (fcntl(*data_pipe, F_SETPIPE_SZ, pipe_size) < 0) {
  67. pr_err("Could not change pipe size in rw-thread(%d)\n", cpu);
  68. goto error;
  69. }
  70. rw_ti->read_pipe = data_pipe[1];
  71. rw_ti->write_pipe = data_pipe[0];
  72. rw_ti->pipe_size = pipe_size;
  73. return NULL;
  74. error:
  75. exit(EXIT_FAILURE);
  76. }
  77. /* Bind a thread to a cpu */
  78. static void bind_cpu(int cpu_num)
  79. {
  80. cpu_set_t mask;
  81. CPU_ZERO(&mask);
  82. CPU_SET(cpu_num, &mask);
  83. /* bind my thread to cpu_num by assigning zero to the first argument */
  84. if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
  85. pr_err("Could not set CPU#%d affinity\n", (int)cpu_num);
  86. }
  87. static void *rw_thread_main(void *thread_info)
  88. {
  89. ssize_t rlen, wlen;
  90. ssize_t ret;
  91. struct rw_thread_info *ts = (struct rw_thread_info *)thread_info;
  92. bind_cpu(ts->cpu_num);
  93. while (1) {
  94. /* Wait for a read order of trace data by Host OS */
  95. if (!global_run_operation) {
  96. pthread_mutex_lock(&mutex_notify);
  97. pthread_cond_wait(&cond_wakeup, &mutex_notify);
  98. pthread_mutex_unlock(&mutex_notify);
  99. }
  100. if (global_sig_receive)
  101. break;
  102. /*
  103. * Each thread read trace_pipe_raw of each cpu bounding the
  104. * thread, so contention of multi-threads does not occur.
  105. */
  106. rlen = splice(ts->in_fd, NULL, ts->read_pipe, NULL,
  107. ts->pipe_size, SPLICE_F_MOVE | SPLICE_F_MORE);
  108. if (rlen < 0) {
  109. pr_err("Splice_read in rw-thread(%d)\n", ts->cpu_num);
  110. goto error;
  111. } else if (rlen == 0) {
  112. /*
  113. * If trace data do not exist or are unreadable not
  114. * for exceeding the page size, splice_read returns
  115. * NULL. Then, this waits for being filled the data in a
  116. * ring-buffer.
  117. */
  118. usleep(READ_WAIT_USEC);
  119. pr_debug("Read retry(cpu:%d)\n", ts->cpu_num);
  120. continue;
  121. }
  122. wlen = 0;
  123. do {
  124. ret = splice(ts->write_pipe, NULL, ts->out_fd, NULL,
  125. rlen - wlen,
  126. SPLICE_F_MOVE | SPLICE_F_MORE);
  127. if (ret < 0) {
  128. pr_err("Splice_write in rw-thread(%d)\n",
  129. ts->cpu_num);
  130. goto error;
  131. } else if (ret == 0)
  132. /*
  133. * When host reader is not in time for reading
  134. * trace data, guest will be stopped. This is
  135. * because char dev in QEMU is not supported
  136. * non-blocking mode. Then, writer might be
  137. * sleep in that case.
  138. * This sleep will be removed by supporting
  139. * non-blocking mode.
  140. */
  141. sleep(1);
  142. wlen += ret;
  143. } while (wlen < rlen);
  144. }
  145. return NULL;
  146. error:
  147. exit(EXIT_FAILURE);
  148. }
  149. pthread_t rw_thread_run(struct rw_thread_info *rw_ti)
  150. {
  151. int ret;
  152. pthread_t rw_thread_per_cpu;
  153. ret = pthread_create(&rw_thread_per_cpu, NULL, rw_thread_main, rw_ti);
  154. if (ret != 0) {
  155. pr_err("Could not create a rw thread(%d)\n", rw_ti->cpu_num);
  156. exit(EXIT_FAILURE);
  157. }
  158. return rw_thread_per_cpu;
  159. }