]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/system/systest_runnable.cc
update sources to v12.1.0
[ceph.git] / ceph / src / test / system / systest_runnable.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include "include/compat.h"
16 #include "common/errno.h"
17 #include "systest_runnable.h"
18 #include "systest_settings.h"
19
20 #include <errno.h>
21 #include <pthread.h>
22 #include <sstream>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <string>
28 #include <sys/syscall.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <unistd.h>
32 #include <vector>
33 #include <atomic>
34
35 using std::ostringstream;
36 using std::string;
37
38 static pid_t do_gettid(void)
39 {
40 #if defined(__linux__)
41 return static_cast < pid_t >(syscall(SYS_gettid));
42 #else
43 return static_cast < pid_t >(pthread_getthreadid_np());
44 #endif
45 }
46
47 std::atomic<unsigned> m_highest_id = { 0 };
48
49 SysTestRunnable::
50 SysTestRunnable(int argc, const char **argv)
51 : m_argc(0),
52 m_argv(NULL),
53 m_argv_orig(NULL)
54 {
55 m_started = false;
56 m_id = ++m_highest_id;
57 memset(&m_pthread, 0, sizeof(m_pthread));
58 update_id_str(false);
59 set_argv(argc, argv);
60 }
61
62 SysTestRunnable::
63 ~SysTestRunnable()
64 {
65 set_argv(0, NULL);
66 }
67
68 const char* SysTestRunnable::
69 get_id_str(void) const
70 {
71 return m_id_str;
72 }
73
74 int SysTestRunnable::
75 start()
76 {
77 if (m_started) {
78 return -EDOM;
79 }
80 int ret;
81 bool use_threads = SysTestSettings::inst().use_threads();
82 if (use_threads) {
83 ret = pthread_create(&m_pthread, NULL, systest_runnable_pthread_helper,
84 static_cast<void*>(this));
85 if (ret)
86 return ret;
87 m_started = true;
88 } else {
89 std::string err_msg;
90 ret = preforker.prefork(err_msg);
91 if (ret < 0)
92 preforker.exit(ret);
93
94 if (preforker.is_child()) {
95 m_started = true;
96 void *retptr = systest_runnable_pthread_helper(static_cast<void*>(this));
97 preforker.exit((int)(uintptr_t)retptr);
98 } else {
99 m_started = true;
100 }
101 }
102 return 0;
103 }
104
105 std::string SysTestRunnable::
106 join()
107 {
108 if (!m_started) {
109 return "SysTestRunnable was never started.";
110 }
111 int ret;
112 bool use_threads = SysTestSettings::inst().use_threads();
113 if (use_threads) {
114 void *ptrretval;
115 ret = pthread_join(m_pthread, &ptrretval);
116 if (ret) {
117 ostringstream oss;
118 oss << "pthread_join failed with error " << ret;
119 return oss.str();
120 }
121 int retval = (int)(uintptr_t)ptrretval;
122 if (retval != 0) {
123 ostringstream oss;
124 oss << "ERROR " << retval;
125 return oss.str();
126 }
127 return "";
128 } else {
129 std::string err_msg;
130 ret = preforker.parent_wait(err_msg);
131 return err_msg;
132 }
133 }
134
135 std::string SysTestRunnable::
136 run_until_finished(std::vector < SysTestRunnable * > &runnables)
137 {
138 int index = 0;
139 for (std::vector < SysTestRunnable * >::const_iterator r = runnables.begin();
140 r != runnables.end(); ++r) {
141 int ret = (*r)->start();
142 if (ret) {
143 ostringstream oss;
144 oss << "run_until_finished: got error " << ret
145 << " when starting runnable " << index;
146 return oss.str();
147 }
148 ++index;
149 }
150
151 for (std::vector < SysTestRunnable * >::const_iterator r = runnables.begin();
152 r != runnables.end(); ++r) {
153 std::string rstr = (*r)->join();
154 if (!rstr.empty()) {
155 ostringstream oss;
156 oss << "run_until_finished: runnable " << (*r)->get_id_str()
157 << ": got error: " << rstr;
158 return oss.str();
159 }
160 }
161 printf("*******************************\n");
162 return "";
163 }
164
165 void *systest_runnable_pthread_helper(void *arg)
166 {
167 SysTestRunnable *st = static_cast < SysTestRunnable * >(arg);
168 st->update_id_str(true);
169 printf("%s: starting.\n", st->get_id_str());
170 int ret = st->run();
171 printf("%s: shutting down.\n", st->get_id_str());
172 return (void*)(uintptr_t)ret;
173 }
174
175 void SysTestRunnable::
176 update_id_str(bool started)
177 {
178 bool use_threads = SysTestSettings::inst().use_threads();
179 char extra[128];
180 extra[0] = '\0';
181
182 if (started) {
183 if (use_threads)
184 snprintf(extra, sizeof(extra), "_[%d]", do_gettid());
185 else
186 snprintf(extra, sizeof(extra), "_[%d]", getpid());
187 }
188 if (use_threads)
189 snprintf(m_id_str, SysTestRunnable::ID_STR_SZ, "thread_%d%s", m_id, extra);
190 else
191 snprintf(m_id_str, SysTestRunnable::ID_STR_SZ, "process_%d%s", m_id, extra);
192 }
193
194 // Copy argv so that if some fiend decides to modify it, it's ok.
195 void SysTestRunnable::
196 set_argv(int argc, const char **argv)
197 {
198 if (m_argv_orig != NULL) {
199 for (int i = 0; i < m_argc; ++i)
200 free((void*)(m_argv_orig[i]));
201 delete[] m_argv_orig;
202 m_argv_orig = NULL;
203 delete[] m_argv;
204 m_argv = NULL;
205 m_argc = 0;
206 }
207 if (argv == NULL)
208 return;
209 m_argc = argc;
210 m_argv_orig = new const char*[m_argc+1];
211 for (int i = 0; i < m_argc; ++i)
212 m_argv_orig[i] = strdup(argv[i]);
213 m_argv_orig[argc] = NULL;
214 m_argv = new const char*[m_argc+1];
215 for (int i = 0; i <= m_argc; ++i)
216 m_argv[i] = m_argv_orig[i];
217 }