| // 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 |