-
Notifications
You must be signed in to change notification settings - Fork 4k
/
Copy pathid.h
193 lines (167 loc) · 8.85 KB
/
id.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// 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_ID_H
#define BTHREAD_ID_H
#include "butil/macros.h" // BAIDU_SYMBOLSTR
#include "bthread/types.h"
__BEGIN_DECLS
// ----------------------------------------------------------------------
// Functions to create 64-bit identifiers that can be attached with data
// and locked without ABA issues. All functions can be called from
// multiple threads simultaneously. Notice that bthread_id_t is designed
// for managing a series of non-heavily-contended actions on an object.
// It's slower than mutex and not proper for general synchronizations.
// ----------------------------------------------------------------------
// Create a bthread_id_t and put it into *id. Crash when `id' is NULL.
// id->value will never be zero.
// `on_error' will be called after bthread_id_error() is called.
// -------------------------------------------------------------------------
// ! User must call bthread_id_unlock() or bthread_id_unlock_and_destroy()
// ! inside on_error.
// -------------------------------------------------------------------------
// Returns 0 on success, error code otherwise.
int bthread_id_create(
bthread_id_t* id, void* data,
int (*on_error)(bthread_id_t id, void* data, int error_code));
// When this function is called successfully, *id, *id+1 ... *id + range - 1
// are mapped to same internal entity. Operations on any of the id work as
// if they're manipulating a same id. `on_error' is called with the id issued
// by corresponding bthread_id_error(). This is designed to let users encode
// versions into identifiers.
// `range' is limited inside [1, 1024].
int bthread_id_create_ranged(
bthread_id_t* id, void* data,
int (*on_error)(bthread_id_t id, void* data, int error_code),
int range);
// Wait until `id' being destroyed.
// Waiting on a destroyed bthread_id_t returns immediately.
// Returns 0 on success, error code otherwise.
int bthread_id_join(bthread_id_t id);
// Destroy a created but never-used bthread_id_t.
// Returns 0 on success, EINVAL otherwise.
int bthread_id_cancel(bthread_id_t id);
// Issue an error to `id'.
// If `id' is not locked, lock the id and run `on_error' immediately. Otherwise
// `on_error' will be called with the error just before `id' being unlocked.
// If `id' is destroyed, un-called on_error are dropped.
// Returns 0 on success, error code otherwise.
#define bthread_id_error(id, err) \
bthread_id_error_verbose(id, err, __FILE__ ":" BAIDU_SYMBOLSTR(__LINE__))
int bthread_id_error_verbose(bthread_id_t id, int error_code,
const char *location);
// Make other bthread_id_lock/bthread_id_trylock on the id fail, the id must
// already be locked. If the id is unlocked later rather than being destroyed,
// effect of this function is cancelled. This function avoids useless
// waiting on a bthread_id which will be destroyed soon but still needs to
// be joinable.
// Returns 0 on success, error code otherwise.
int bthread_id_about_to_destroy(bthread_id_t id);
// Try to lock `id' (for using the data exclusively)
// On success return 0 and set `pdata' with the `data' parameter to
// bthread_id_create[_ranged], EBUSY on already locked, error code otherwise.
int bthread_id_trylock(bthread_id_t id, void** pdata);
// Lock `id' (for using the data exclusively). If `id' is locked
// by others, wait until `id' is unlocked or destroyed.
// On success return 0 and set `pdata' with the `data' parameter to
// bthread_id_create[_ranged], error code otherwise.
#define bthread_id_lock(id, pdata) \
bthread_id_lock_verbose(id, pdata, __FILE__ ":" BAIDU_SYMBOLSTR(__LINE__))
int bthread_id_lock_verbose(bthread_id_t id, void** pdata,
const char *location);
// Lock `id' (for using the data exclusively) and reset the range. If `id' is
// locked by others, wait until `id' is unlocked or destroyed. if `range' is
// smaller than the original range of this id, nothing happens about the range
#define bthread_id_lock_and_reset_range(id, pdata, range) \
bthread_id_lock_and_reset_range_verbose(id, pdata, range, \
__FILE__ ":" BAIDU_SYMBOLSTR(__LINE__))
int bthread_id_lock_and_reset_range_verbose(
bthread_id_t id, void **pdata,
int range, const char *location);
// Unlock `id'. Must be called after a successful call to bthread_id_trylock()
// or bthread_id_lock().
// Returns 0 on success, error code otherwise.
int bthread_id_unlock(bthread_id_t id);
// Unlock and destroy `id'. Waiters blocking on bthread_id_join() or
// bthread_id_lock() will wake up. Must be called after a successful call to
// bthread_id_trylock() or bthread_id_lock().
// Returns 0 on success, error code otherwise.
int bthread_id_unlock_and_destroy(bthread_id_t id);
// **************************************************************************
// bthread_id_list_xxx functions are NOT thread-safe unless explicitly stated
// Initialize a list for storing bthread_id_t. When an id is destroyed, it will
// be removed from the list automatically.
// The commented parameters are not used anymore and just kept to not break
// compatibility.
int bthread_id_list_init(bthread_id_list_t* list,
unsigned /*size*/,
unsigned /*conflict_size*/);
// Destroy the list.
void bthread_id_list_destroy(bthread_id_list_t* list);
// Add a bthread_id_t into the list.
int bthread_id_list_add(bthread_id_list_t* list, bthread_id_t id);
// Swap internal fields of two lists.
void bthread_id_list_swap(bthread_id_list_t* dest,
bthread_id_list_t* src);
// Issue error_code to all bthread_id_t inside `list' and clear `list'.
// Notice that this function iterates all id inside the list and may call
// on_error() of each valid id in-place, in another word, this thread-unsafe
// function is not suitable to be enclosed within a lock directly.
// To make the critical section small, swap the list inside the lock and
// reset the swapped list outside the lock as follows:
// bthread_id_list_t tmplist;
// bthread_id_list_init(&tmplist, 0, 0);
// LOCK;
// bthread_id_list_swap(&tmplist, &the_list_to_reset);
// UNLOCK;
// bthread_id_list_reset(&tmplist, error_code);
// bthread_id_list_destroy(&tmplist);
int bthread_id_list_reset(bthread_id_list_t* list, int error_code);
// Following 2 functions wrap above process.
int bthread_id_list_reset_pthreadsafe(
bthread_id_list_t* list, int error_code, pthread_mutex_t* mutex);
int bthread_id_list_reset_bthreadsafe(
bthread_id_list_t* list, int error_code, bthread_mutex_t* mutex);
__END_DECLS
#if defined(__cplusplus)
// cpp specific API, with an extra `error_text' so that error information
// is more comprehensive
int bthread_id_create2(
bthread_id_t* id, void* data,
int (*on_error)(bthread_id_t id, void* data, int error_code,
const std::string& error_text));
int bthread_id_create2_ranged(
bthread_id_t* id, void* data,
int (*on_error)(bthread_id_t id, void* data, int error_code,
const std::string& error_text),
int range);
#define bthread_id_error2(id, ec, et) \
bthread_id_error2_verbose(id, ec, et, __FILE__ ":" BAIDU_SYMBOLSTR(__LINE__))
int bthread_id_error2_verbose(bthread_id_t id, int error_code,
const std::string& error_text,
const char *location);
int bthread_id_list_reset2(bthread_id_list_t* list, int error_code,
const std::string& error_text);
int bthread_id_list_reset2_pthreadsafe(bthread_id_list_t* list, int error_code,
const std::string& error_text,
pthread_mutex_t* mutex);
int bthread_id_list_reset2_bthreadsafe(bthread_id_list_t* list, int error_code,
const std::string& error_text,
bthread_mutex_t* mutex);
#endif
#endif // BTHREAD_ID_H