]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/Thread.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / common / Thread.cc
CommitLineData
7c673cae
FG
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) 2004-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
11fdf7f2
TL
15#include <signal.h>
16#include <unistd.h>
17#ifdef __linux__
18#include <sys/syscall.h> /* For SYS_xxx definitions */
19#endif
20
f67539c2
TL
21#ifdef WITH_SEASTAR
22#include "crimson/os/alienstore/alien_store.h"
23#endif
24
7c673cae
FG
25#include "common/Thread.h"
26#include "common/code_environment.h"
27#include "common/debug.h"
28#include "common/signal.h"
7c673cae 29
7c673cae
FG
30#ifdef HAVE_SCHED
31#include <sched.h>
32#endif
33
11fdf7f2
TL
34
35pid_t ceph_gettid(void)
36{
37#ifdef __linux__
38 return syscall(SYS_gettid);
39#else
40 return -ENOSYS;
41#endif
42}
43
7c673cae
FG
44static int _set_affinity(int id)
45{
46#ifdef HAVE_SCHED
47 if (id >= 0 && id < CPU_SETSIZE) {
48 cpu_set_t cpuset;
49 CPU_ZERO(&cpuset);
50
51 CPU_SET(id, &cpuset);
52
53 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) < 0)
54 return -errno;
55 /* guaranteed to take effect immediately */
56 sched_yield();
57 }
58#endif
59 return 0;
60}
61
62Thread::Thread()
63 : thread_id(0),
64 pid(0),
f67539c2 65 cpuid(-1)
7c673cae
FG
66{
67}
68
69Thread::~Thread()
70{
71}
72
73void *Thread::_entry_func(void *arg) {
74 void *r = ((Thread*)arg)->entry_wrapper();
75 return r;
76}
77
78void *Thread::entry_wrapper()
79{
80 int p = ceph_gettid(); // may return -ENOSYS on other platforms
81 if (p > 0)
82 pid = p;
7c673cae
FG
83 if (pid && cpuid >= 0)
84 _set_affinity(cpuid);
85
f67539c2 86 ceph_pthread_setname(pthread_self(), thread_name.c_str());
7c673cae
FG
87 return entry();
88}
89
90const pthread_t &Thread::get_thread_id() const
91{
92 return thread_id;
93}
94
95bool Thread::is_started() const
96{
97 return thread_id != 0;
98}
99
100bool Thread::am_self() const
101{
102 return (pthread_self() == thread_id);
103}
104
105int Thread::kill(int signal)
106{
107 if (thread_id)
108 return pthread_kill(thread_id, signal);
109 else
110 return -EINVAL;
111}
112
113int Thread::try_create(size_t stacksize)
114{
115 pthread_attr_t *thread_attr = NULL;
116 pthread_attr_t thread_attr_loc;
117
118 stacksize &= CEPH_PAGE_MASK; // must be multiple of page
119 if (stacksize) {
120 thread_attr = &thread_attr_loc;
121 pthread_attr_init(thread_attr);
122 pthread_attr_setstacksize(thread_attr, stacksize);
123 }
124
125 int r;
126
127 // The child thread will inherit our signal mask. Set our signal mask to
128 // the set of signals we want to block. (It's ok to block signals more
129 // signals than usual for a little while-- they will just be delivered to
130 // another thread or delieverd to this thread later.)
f67539c2
TL
131
132 #ifndef _WIN32
7c673cae
FG
133 sigset_t old_sigset;
134 if (g_code_env == CODE_ENVIRONMENT_LIBRARY) {
135 block_signals(NULL, &old_sigset);
136 }
137 else {
138 int to_block[] = { SIGPIPE , 0 };
139 block_signals(to_block, &old_sigset);
140 }
141 r = pthread_create(&thread_id, thread_attr, _entry_func, (void*)this);
142 restore_sigset(&old_sigset);
f67539c2
TL
143 #else
144 r = pthread_create(&thread_id, thread_attr, _entry_func, (void*)this);
145 #endif
7c673cae
FG
146
147 if (thread_attr) {
148 pthread_attr_destroy(thread_attr);
149 }
150
151 return r;
152}
153
154void Thread::create(const char *name, size_t stacksize)
155{
11fdf7f2 156 ceph_assert(strlen(name) < 16);
7c673cae
FG
157 thread_name = name;
158
159 int ret = try_create(stacksize);
160 if (ret != 0) {
161 char buf[256];
162 snprintf(buf, sizeof(buf), "Thread::try_create(): pthread_create "
163 "failed with error %d", ret);
164 dout_emergency(buf);
11fdf7f2 165 ceph_assert(ret == 0);
7c673cae
FG
166 }
167}
168
169int Thread::join(void **prval)
170{
171 if (thread_id == 0) {
11fdf7f2 172 ceph_abort_msg("join on thread that was never started");
7c673cae
FG
173 return -EINVAL;
174 }
175
176 int status = pthread_join(thread_id, prval);
177 if (status != 0) {
178 char buf[256];
179 snprintf(buf, sizeof(buf), "Thread::join(): pthread_join "
180 "failed with error %d\n", status);
181 dout_emergency(buf);
11fdf7f2 182 ceph_assert(status == 0);
7c673cae
FG
183 }
184
185 thread_id = 0;
186 return status;
187}
188
189int Thread::detach()
190{
191 return pthread_detach(thread_id);
192}
193
7c673cae
FG
194int Thread::set_affinity(int id)
195{
196 int r = 0;
197 cpuid = id;
198 if (pid && ceph_gettid() == pid)
199 r = _set_affinity(id);
200 return r;
201}
11fdf7f2
TL
202
203// Functions for std::thread
204// =========================
205
206void set_thread_name(std::thread& t, const std::string& s) {
207 int r = ceph_pthread_setname(t.native_handle(), s.c_str());
208 if (r != 0) {
209 throw std::system_error(r, std::generic_category());
210 }
211}
212std::string get_thread_name(const std::thread& t) {
213 std::string s(256, '\0');
214
215 int r = ceph_pthread_getname(const_cast<std::thread&>(t).native_handle(),
216 s.data(), s.length());
217 if (r != 0) {
218 throw std::system_error(r, std::generic_category());
219 }
220 s.resize(std::strlen(s.data()));
221 return s;
222}
223
224void kill(std::thread& t, int signal)
225{
226 auto r = pthread_kill(t.native_handle(), signal);
227 if (r != 0) {
228 throw std::system_error(r, std::generic_category());
229 }
230}