blob: 86148c938bfec2f084bb4551311b4253b4068045 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// bthread - An M:N threading library to make applications more concurrent.
// Date: Tue Jul 10 17:40:58 CST 2012
#ifndef BTHREAD_TYPES_H
#define BTHREAD_TYPES_H
#include <stdint.h> // uint64_t
#include "butil/macros.h"
#if defined(__cplusplus)
#include "butil/logging.h" // CHECK
#endif
typedef uint64_t bthread_t;
// tid returned by bthread_start_* never equals this value.
static const bthread_t INVALID_BTHREAD = 0;
// bthread tag default is 0
typedef int bthread_tag_t;
static const bthread_tag_t BTHREAD_TAG_INVALID = -1;
static const bthread_tag_t BTHREAD_TAG_DEFAULT = 0;
struct sockaddr;
typedef unsigned bthread_stacktype_t;
static const bthread_stacktype_t BTHREAD_STACKTYPE_UNKNOWN = 0;
static const bthread_stacktype_t BTHREAD_STACKTYPE_PTHREAD = 1;
static const bthread_stacktype_t BTHREAD_STACKTYPE_SMALL = 2;
static const bthread_stacktype_t BTHREAD_STACKTYPE_NORMAL = 3;
static const bthread_stacktype_t BTHREAD_STACKTYPE_LARGE = 4;
typedef unsigned bthread_attrflags_t;
static const bthread_attrflags_t BTHREAD_LOG_START_AND_FINISH = 8;
static const bthread_attrflags_t BTHREAD_LOG_CONTEXT_SWITCH = 16;
static const bthread_attrflags_t BTHREAD_NOSIGNAL = 32;
static const bthread_attrflags_t BTHREAD_NEVER_QUIT = 64;
static const bthread_attrflags_t BTHREAD_INHERIT_SPAN = 128;
static const bthread_attrflags_t BTHREAD_GLOBAL_PRIORITY = 256;
// Key of thread-local data, created by bthread_key_create.
typedef struct {
uint32_t index; // index in KeyTable
uint32_t version; // ABA avoidance
} bthread_key_t;
static const bthread_key_t INVALID_BTHREAD_KEY = { 0, 0 };
#if defined(__cplusplus)
// Overload operators for bthread_key_t
inline bool operator==(bthread_key_t key1, bthread_key_t key2)
{ return key1.index == key2.index && key1.version == key2.version; }
inline bool operator!=(bthread_key_t key1, bthread_key_t key2)
{ return !(key1 == key2); }
inline bool operator<(bthread_key_t key1, bthread_key_t key2) {
return key1.index != key2.index ? (key1.index < key2.index) :
(key1.version < key2.version);
}
inline bool operator>(bthread_key_t key1, bthread_key_t key2)
{ return key2 < key1; }
inline bool operator<=(bthread_key_t key1, bthread_key_t key2)
{ return !(key2 < key1); }
inline bool operator>=(bthread_key_t key1, bthread_key_t key2)
{ return !(key1 < key2); }
inline std::ostream& operator<<(std::ostream& os, bthread_key_t key) {
return os << "bthread_key_t{index=" << key.index << " version="
<< key.version << '}';
}
#endif // __cplusplus
typedef struct {
pthread_rwlock_t rwlock;
void* list;
void* free_keytables;
size_t size;
int destroyed;
} bthread_keytable_pool_t;
typedef struct {
size_t nfree;
} bthread_keytable_pool_stat_t;
static const size_t BTHREAD_NAME_MAX_LENGTH = 31;
// Attributes for thread creation.
typedef struct bthread_attr_t {
bthread_stacktype_t stack_type;
bthread_attrflags_t flags;
bthread_keytable_pool_t* keytable_pool;
bthread_tag_t tag;
char name[BTHREAD_NAME_MAX_LENGTH + 1]; // do not use std::string to keep POD
#if defined(__cplusplus)
void operator=(unsigned stacktype_and_flags) {
stack_type = (stacktype_and_flags & 7);
flags = (stacktype_and_flags & ~(unsigned)7u);
keytable_pool = NULL;
tag = BTHREAD_TAG_INVALID;
}
bthread_attr_t operator|(unsigned other_flags) const {
CHECK(!(other_flags & 7)) << "flags=" << other_flags;
bthread_attr_t tmp = *this;
tmp.flags |= (other_flags & ~(unsigned)7u);
return tmp;
}
#endif // __cplusplus
} bthread_attr_t;
void bthread_attr_set_name(bthread_attr_t* attr, const char* name);
// bthreads started with this attribute will run on stack of worker pthread and
// all bthread functions that would block the bthread will block the pthread.
// The bthread will not allocate its own stack, simply occupying a little meta
// memory. This is required to run JNI code which checks layout of stack. The
// obvious drawback is that you need more worker pthreads when you have a lot
// of such bthreads.
static const bthread_attr_t BTHREAD_ATTR_PTHREAD =
{ BTHREAD_STACKTYPE_PTHREAD, 0, NULL, BTHREAD_TAG_INVALID, {0} };
// bthreads created with following attributes will have different size of
// stacks. Default is BTHREAD_ATTR_NORMAL.
static const bthread_attr_t BTHREAD_ATTR_SMALL = {BTHREAD_STACKTYPE_SMALL, 0, NULL,
BTHREAD_TAG_INVALID, {0}};
static const bthread_attr_t BTHREAD_ATTR_NORMAL = {BTHREAD_STACKTYPE_NORMAL, 0, NULL,
BTHREAD_TAG_INVALID, {0}};
static const bthread_attr_t BTHREAD_ATTR_LARGE = {BTHREAD_STACKTYPE_LARGE, 0, NULL,
BTHREAD_TAG_INVALID, {0}};
// bthreads created with this attribute will print log when it's started,
// context-switched, finished.
static const bthread_attr_t BTHREAD_ATTR_DEBUG = {
BTHREAD_STACKTYPE_NORMAL, BTHREAD_LOG_START_AND_FINISH | BTHREAD_LOG_CONTEXT_SWITCH, NULL,
BTHREAD_TAG_INVALID, {0}};
static const size_t BTHREAD_EPOLL_THREAD_NUM = 1;
static const bthread_t BTHREAD_ATOMIC_INIT = 0;
// Min/Max number of work pthreads.
static const int BTHREAD_MIN_CONCURRENCY = 3 + BTHREAD_EPOLL_THREAD_NUM;
static const int BTHREAD_MAX_CONCURRENCY = 1024;
// Min/max number of ParkingLot.
static const int BTHREAD_MIN_PARKINGLOT = 4;
static const int BTHREAD_MAX_PARKINGLOT = 1024;
typedef struct {
void* impl;
// following fields are part of previous impl. and not used right now.
// Don't remove them to break ABI compatibility.
unsigned head;
unsigned size;
unsigned conflict_head;
unsigned conflict_size;
} bthread_list_t;
// TODO: bthread_contention_site_t should be put into butex.
typedef struct {
int64_t duration_ns;
size_t sampling_range;
} bthread_contention_site_t;
struct mutex_owner_t {
bool hold;
uint64_t id;
};
typedef struct bthread_mutex_t {
#if defined(__cplusplus)
bthread_mutex_t()
: butex(NULL), csite{}
, enable_csite(false)
, owner{false, 0} {}
DISALLOW_COPY_AND_ASSIGN(bthread_mutex_t);
#endif
unsigned* butex;
bthread_contention_site_t csite;
bool enable_csite;
// Note: Owner detection of the mutex comes with average execution
// slowdown of about 50%, so it is only used for debugging and is
// only available when the macro `BRPC_DEBUG_LOCK' = 1.
mutex_owner_t owner;
} bthread_mutex_t;
typedef struct {
bool enable_csite;
} bthread_mutexattr_t;
typedef struct bthread_cond_t {
#if defined(__cplusplus)
bthread_cond_t() : m(NULL), seq(NULL) {}
DISALLOW_COPY_AND_ASSIGN(bthread_cond_t);
#endif
bthread_mutex_t* m;
int* seq;
} bthread_cond_t;
typedef struct {
} bthread_condattr_t;
typedef struct bthread_sem_t {
#if defined(__cplusplus)
bthread_sem_t() : butex(NULL), enable_csite(true) {}
DISALLOW_COPY_AND_ASSIGN(bthread_sem_t);
#endif
unsigned* butex;
bool enable_csite;
} bthread_sem_t;
typedef struct bthread_rwlock_t {
#if defined(__cplusplus)
bthread_rwlock_t()
: reader_count(0), reader_wait(0), wlock_flag(false), writer_csite{} {}
DISALLOW_COPY_AND_ASSIGN(bthread_rwlock_t);
#endif
bthread_sem_t reader_sema; // Semaphore for readers to wait for completing writers.
bthread_sem_t writer_sema; // Semaphore for writers to wait for completing readers.
int reader_count; // Number of pending readers.
int reader_wait; // Number of departing readers.
bool wlock_flag; // Flag used to indicate that a write lock has been held.
bthread_mutex_t write_queue_mutex; // Held if there are pending writers.
bthread_contention_site_t writer_csite;
} bthread_rwlock_t;
typedef struct {
} bthread_rwlockattr_t;
typedef struct {
unsigned int count;
} bthread_barrier_t;
typedef struct {
} bthread_barrierattr_t;
#if defined(__cplusplus)
class bthread_once_t;
namespace bthread {
extern int bthread_once_impl(bthread_once_t* once_control, void (*init_routine)());
}
class bthread_once_t {
public:
friend int bthread::bthread_once_impl(bthread_once_t* once_control, void (*init_routine)());
enum State {
UNINITIALIZED = 0,
INPROGRESS,
INITIALIZED,
};
bthread_once_t();
~bthread_once_t();
DISALLOW_COPY_AND_ASSIGN(bthread_once_t);
private:
butil::atomic<int>* _butex;
};
#endif
typedef struct {
uint64_t value;
} bthread_id_t;
// bthread_id returned by bthread_id_create* can never be this value.
// NOTE: don't confuse with INVALID_BTHREAD!
static const bthread_id_t INVALID_BTHREAD_ID = {0};
#if defined(__cplusplus)
// Overload operators for bthread_id_t
inline bool operator==(bthread_id_t id1, bthread_id_t id2)
{ return id1.value == id2.value; }
inline bool operator!=(bthread_id_t id1, bthread_id_t id2)
{ return !(id1 == id2); }
inline bool operator<(bthread_id_t id1, bthread_id_t id2)
{ return id1.value < id2.value; }
inline bool operator>(bthread_id_t id1, bthread_id_t id2)
{ return id2 < id1; }
inline bool operator<=(bthread_id_t id1, bthread_id_t id2)
{ return !(id2 < id1); }
inline bool operator>=(bthread_id_t id1, bthread_id_t id2)
{ return !(id1 < id2); }
inline std::ostream& operator<<(std::ostream& os, bthread_id_t id)
{ return os << id.value; }
#endif // __cplusplus
typedef struct {
void* impl;
// following fields are part of previous impl. and not used right now.
// Don't remove them to break ABI compatibility.
unsigned head;
unsigned size;
unsigned conflict_head;
unsigned conflict_size;
} bthread_id_list_t;
typedef uint64_t bthread_timer_t;
#endif // BTHREAD_TYPES_H