mirror of
https://github.com/ceph/ceph
synced 2026-08-01 22:45:39 +00:00
213 lines
4.2 KiB
C++
213 lines
4.2 KiB
C++
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
|
|
// vim: ts=8 sw=2 smarttab
|
|
/*
|
|
* Ceph - scalable distributed file system
|
|
*
|
|
* Copyright (C) 2004-2011 New Dream Network
|
|
*
|
|
* This is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License version 2.1, as published by the Free Software
|
|
* Foundation. See file COPYING.
|
|
*
|
|
*/
|
|
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#ifdef __linux__
|
|
#include <sys/syscall.h> /* For SYS_xxx definitions */
|
|
#endif
|
|
|
|
#ifdef WITH_CRIMSON
|
|
#include "crimson/os/alienstore/alien_store.h"
|
|
#endif
|
|
|
|
#include "common/Thread.h"
|
|
#include "common/code_environment.h"
|
|
#include "common/debug.h"
|
|
#include "common/signal.h"
|
|
|
|
#ifdef HAVE_SCHED
|
|
#include <sched.h>
|
|
#endif
|
|
|
|
|
|
pid_t ceph_gettid(void)
|
|
{
|
|
#ifdef __linux__
|
|
return syscall(SYS_gettid);
|
|
#else
|
|
return -ENOSYS;
|
|
#endif
|
|
}
|
|
|
|
static int _set_affinity(int id)
|
|
{
|
|
#ifdef HAVE_SCHED
|
|
if (id >= 0 && id < CPU_SETSIZE) {
|
|
cpu_set_t cpuset;
|
|
CPU_ZERO(&cpuset);
|
|
|
|
CPU_SET(id, &cpuset);
|
|
|
|
if (sched_setaffinity(0, sizeof(cpuset), &cpuset) < 0)
|
|
return -errno;
|
|
/* guaranteed to take effect immediately */
|
|
sched_yield();
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
Thread::Thread()
|
|
: thread_id(0),
|
|
pid(0),
|
|
cpuid(-1)
|
|
{
|
|
}
|
|
|
|
Thread::~Thread()
|
|
{
|
|
}
|
|
|
|
void *Thread::_entry_func(void *arg) {
|
|
void *r = ((Thread*)arg)->entry_wrapper();
|
|
return r;
|
|
}
|
|
|
|
void *Thread::entry_wrapper()
|
|
{
|
|
int p = ceph_gettid(); // may return -ENOSYS on other platforms
|
|
if (p > 0)
|
|
pid = p;
|
|
if (pid && cpuid >= 0)
|
|
_set_affinity(cpuid);
|
|
|
|
ceph_pthread_setname(thread_name.c_str());
|
|
return entry();
|
|
}
|
|
|
|
const pthread_t &Thread::get_thread_id() const
|
|
{
|
|
return thread_id;
|
|
}
|
|
|
|
bool Thread::is_started() const
|
|
{
|
|
return thread_id != 0;
|
|
}
|
|
|
|
bool Thread::am_self() const
|
|
{
|
|
return (pthread_self() == thread_id);
|
|
}
|
|
|
|
int Thread::kill(int signal)
|
|
{
|
|
if (thread_id)
|
|
return pthread_kill(thread_id, signal);
|
|
else
|
|
return -EINVAL;
|
|
}
|
|
|
|
int Thread::try_create(size_t stacksize)
|
|
{
|
|
pthread_attr_t *thread_attr = NULL;
|
|
pthread_attr_t thread_attr_loc;
|
|
|
|
stacksize &= CEPH_PAGE_MASK; // must be multiple of page
|
|
if (stacksize) {
|
|
thread_attr = &thread_attr_loc;
|
|
pthread_attr_init(thread_attr);
|
|
pthread_attr_setstacksize(thread_attr, stacksize);
|
|
}
|
|
|
|
int r;
|
|
|
|
// The child thread will inherit our signal mask. Set our signal mask to
|
|
// the set of signals we want to block. (It's ok to block signals more
|
|
// signals than usual for a little while-- they will just be delivered to
|
|
// another thread or delieverd to this thread later.)
|
|
|
|
#ifndef _WIN32
|
|
sigset_t old_sigset;
|
|
if (g_code_env == CODE_ENVIRONMENT_LIBRARY) {
|
|
block_signals(NULL, &old_sigset);
|
|
}
|
|
else {
|
|
int to_block[] = { SIGPIPE , 0 };
|
|
block_signals(to_block, &old_sigset);
|
|
}
|
|
r = pthread_create(&thread_id, thread_attr, _entry_func, (void*)this);
|
|
restore_sigset(&old_sigset);
|
|
#else
|
|
r = pthread_create(&thread_id, thread_attr, _entry_func, (void*)this);
|
|
#endif
|
|
|
|
if (thread_attr) {
|
|
pthread_attr_destroy(thread_attr);
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
void Thread::create(const char *name, size_t stacksize)
|
|
{
|
|
ceph_assert(strlen(name) < 16);
|
|
thread_name = name;
|
|
|
|
int ret = try_create(stacksize);
|
|
if (ret != 0) {
|
|
char buf[256];
|
|
snprintf(buf, sizeof(buf), "Thread::try_create(): pthread_create "
|
|
"failed with error %d", ret);
|
|
dout_emergency(buf);
|
|
ceph_assert(ret == 0);
|
|
}
|
|
}
|
|
|
|
int Thread::join(void **prval)
|
|
{
|
|
if (thread_id == 0) {
|
|
ceph_abort_msg("join on thread that was never started");
|
|
return -EINVAL;
|
|
}
|
|
|
|
int status = pthread_join(thread_id, prval);
|
|
if (status != 0) {
|
|
char buf[256];
|
|
snprintf(buf, sizeof(buf), "Thread::join(): pthread_join "
|
|
"failed with error %d\n", status);
|
|
dout_emergency(buf);
|
|
ceph_assert(status == 0);
|
|
}
|
|
|
|
thread_id = 0;
|
|
return status;
|
|
}
|
|
|
|
int Thread::detach()
|
|
{
|
|
return pthread_detach(thread_id);
|
|
}
|
|
|
|
int Thread::set_affinity(int id)
|
|
{
|
|
int r = 0;
|
|
cpuid = id;
|
|
if (pid && ceph_gettid() == pid)
|
|
r = _set_affinity(id);
|
|
return r;
|
|
}
|
|
|
|
// Functions for std::thread
|
|
// =========================
|
|
|
|
void kill(std::thread& t, int signal)
|
|
{
|
|
auto r = ceph_pthread_kill(t.native_handle(), signal);
|
|
if (r != 0) {
|
|
throw std::system_error(r, std::generic_category());
|
|
}
|
|
}
|