123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- /*
- * Copyright (c) 2018-2019 SignalWire, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
- #pragma once
- /* Handle states provide hooks to do things when they change, and they
- * describe whether the handle is open for use or not */
- typedef enum {
- SWCLT_HSTATE_INVALID, /* this is the no state, only used to distinguish between set and not set */
- SWCLT_HSTATE_NORMAL, /* the default state, we assume everything is normal post allocation. */
- SWCLT_HSTATE_ONLINE, /* the handle is now 'online' in whatever definition they want to consider it to be */
- SWCLT_HSTATE_OFFLINE, /* the handle is now 'offline' in whatever definition they want to consider it to be */
- SWCLT_HSTATE_DEGRADED, /* the service provided by the handle has halted due to some kind of failure.
- * Note: The primary difference between DEGRADED and OFFLINE is that DEGRADED is
- * caused by some kind of error, wherease OFFLINE may just be a request from the client. */
- } SWCLT_HSTATE;
- /* swclt_hstate_str - Returns a string version for the state enumeration value */
- static inline const char *swclt_hstate_str(SWCLT_HSTATE state)
- {
- switch (state) {
- case SWCLT_HSTATE_INVALID:
- return "Invalid";
- case SWCLT_HSTATE_NORMAL:
- return "Normal";
- case SWCLT_HSTATE_ONLINE:
- return "Online";
- case SWCLT_HSTATE_OFFLINE:
- return "Offline";
- case SWCLT_HSTATE_DEGRADED:
- return "Degraded";
- default:
- ks_abort_fmt("Invalid handle state: %d", state);
- }
- }
- /* Forward declare our handle type as it is composed of inner types that reference it */
- typedef struct swclt_hstate_change_request swclt_hstate_change_t;
- typedef struct swclt_handle_base swclt_handle_base_t;
- /* A state change callback is available on any signalwire client handle */
- typedef void(*swclt_hstate_change_cb_t)(swclt_handle_base_t *ctx, swclt_hstate_change_t *state_change_request);
- /* State change handler for when a handle wants to transition state and execute code as part of the transition */
- typedef ks_status_t (*swclt_hstate_state_change_handler_cb_t)(swclt_handle_base_t *ctx, SWCLT_HSTATE requested_new_state);
- /* Service callback for all client handles */
- typedef void(*swclt_hstate_service_cb_t)(swclt_handle_base_t *ctx);
- /* Context structure used to describe a state change listener on a handle */
- typedef struct swclt_hstate_listener_s {
- swclt_hstate_change_cb_t cb; /* Called anytime state changes on this handle, by the service manager thread */
- ks_handle_t handle; /* We check this ptr out before calling the callers callback */
- } swclt_hstate_listener_t;
- /* The state change request structure gets allocated by the handle anytime it wants to start a state change
- * request. The manager will then take this state change and apply it in its thread */
- struct swclt_hstate_change_request {
- /* the requested state to change to */
- SWCLT_HSTATE new_state;
- /* the original state snapshotted at allocation */
- SWCLT_HSTATE old_state;
- /* Reason and status for the state change (reason must be non zero when
- * state is degraded, and must be zero when state is normal) */
- char *reason;
- ks_status_t status;
- #if defined(KS_BUILD_DEBUG)
- /* For debugging we stash the file/line/tag anytime state changes */
- const char *file;
- const char *tag;
- int line;
- #endif
- };
- /* Describes in detail the pending state change, including the reason and status code. If debug
- * is enabled, will include the file/line where the state change was initiated from. */
- static inline const char *swclt_hstate_describe_change(const swclt_hstate_change_t *pending_state_change)
- {
- static KS_THREAD_LOCAL char buf[1024] = { 0 };
- #if defined(KS_BUILD_DEBUG)
- snprintf(buf, sizeof(buf), "[%s=>%s] Status: %d Reason: %s\nLocation: %s:%d:%s",
- swclt_hstate_str(pending_state_change->old_state),
- swclt_hstate_str(pending_state_change->new_state),
- pending_state_change->status, pending_state_change->reason,
- pending_state_change->file, pending_state_change->line, pending_state_change->tag);
- #else
- snprintf(buf, sizeof(buf), "[%s=>%s] Status: %d Reason: %s",
- swclt_hstate_str(pending_state_change->old_state),
- swclt_hstate_str(pending_state_change->new_state),
- pending_state_change->status, pending_state_change->reason);
- #endif
- return buf;
- }
- /* Private handle state apis used internally, but still exposed for unit tests */
- SWCLT_DECLARE(ks_status_t) swclt_hstate_check_ctx(const swclt_handle_base_t *ctx, const char *log_message);
- SWCLT_DECLARE(SWCLT_HSTATE) swclt_hstate_get_ctx(const swclt_handle_base_t *ctx);
- SWCLT_DECLARE(SWCLT_HSTATE) swclt_hstate_get(ks_handle_t handle);
- SWCLT_DECLARE(SWCLT_HSTATE) swclt_hstate_pending_get(ks_handle_t handle);
- SWCLT_DECLARE(SWCLT_HSTATE) swclt_hstate_current_get(ks_handle_t handle);
- SWCLT_DECLARE(ks_status_t) swclt_hstate_check(ks_handle_t handle, const char *log_message);
- SWCLT_DECLARE(void) __swclt_hstate_changed(swclt_handle_base_t *ctx,SWCLT_HSTATE new_state, ks_status_t status, const char *reason, const char *file, int line, const char *tag);
- SWCLT_DECLARE(void) __swclt_hstate_initiate_change_in(
- swclt_handle_base_t *base,
- SWCLT_HSTATE new_state,
- swclt_hstate_state_change_handler_cb_t cb,
- ks_time_t next_service_ms,
- ks_time_t retry_delay_ms);
- #define swclt_hstate_initiate_change_in(base, new_state, cb, next_service_ms, retry_delay_ms)\
- __swclt_hstate_initiate_change_in(base, new_state, (swclt_hstate_state_change_handler_cb_t)cb, next_service_ms, retry_delay_ms)
- SWCLT_DECLARE(void) __swclt_hstate_initiate_change_now(
- swclt_handle_base_t *base,
- SWCLT_HSTATE new_state,
- swclt_hstate_state_change_handler_cb_t cb,
- ks_time_t retry_delay_ms);
- #define swclt_hstate_initiate_change_now(base, new_state, cb, retry_delay_ms)\
- __swclt_hstate_initiate_change_now(base, new_state, (swclt_hstate_state_change_handler_cb_t)cb, retry_delay_ms)
- SWCLT_DECLARE(ks_status_t) __swclt_hstate_register_listener(
- swclt_handle_base_t *listening_ctx,
- swclt_hstate_change_cb_t state_change_cb,
- ks_handle_t state_change_source_handle,
- const char *file,
- int line,
- const char *tag);
- SWCLT_DECLARE(void) __swclt_hstate_register_service(swclt_handle_base_t *ctx, swclt_hstate_service_cb_t service_cb, const char *file, int line, const char *tag);
- /* Use these macros to forward the context to debug build structures while also providing a cast for
- * the callbacks. */
- #define swclt_hstate_changed(ctx, new_state, status, reason) __swclt_hstate_changed(ctx, new_state, status, reason, __FILE__, __LINE__, __PRETTY_FUNCTION__)
- #define swclt_hstate_register_listener(ctx, cb, handle) __swclt_hstate_register_listener((swclt_handle_base_t *)ctx, (swclt_hstate_change_cb_t)cb, handle, __FILE__, __LINE__, __PRETTY_FUNCTION__)
- #define swclt_hstate_register_service(ctx, service_cb) __swclt_hstate_register_service(ctx, (swclt_hstate_service_cb_t)service_cb, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|