trace-agent-rw.c 4.3 KB

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