/* * Copyright (c) 2013-2016 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #ifndef __OS_ACTIVITY_H__ #define __OS_ACTIVITY_H__ #include #include #include #include #include __BEGIN_DECLS #if ((defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0) \ || (defined(__WATCH_OS_VERSION_MIN_REQUIRED) && __WATCH_OS_VERSION_MIN_REQUIRED >= __WATCHOS_3_0) \ || (defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED >= __TVOS_10_0) \ || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_12)) #define OS_ACTIVITY_OBJECT_API 1 #else #if OS_ACTIVITY_OBJECT_API #error Please change your minimum OS requirements because OS_ACTIVITY_OBJECT_API is not available #endif // OS_ACTIVITY_OBJECT_API #define OS_ACTIVITY_OBJECT_API 0 #endif extern void* __dso_handle; #define OS_LOG_STRING(_var, _str) \ _Static_assert(__builtin_constant_p(_str), "formatters/labels/descriptions must be a constant string"); \ __attribute__((section("__TEXT,__oslogstring,cstring_literals"),internal_linkage)) static const char _var[] __asm(OS_STRINGIFY(OS_CONCAT(LOSACTIVITY_, __COUNTER__))) = _str /*! * @typedef os_breadcrumb_t * An opaque value for the breadcrumb ID. */ __API_DEPRECATED("No longer supported", macosx(10.10, 10.12), ios(8.0, 10.0), watchos(2.0, 3.0), tvos(9.0, 10.0)) typedef uint32_t os_breadcrumb_t; #define OS_ACTIVITY_NULL 0 /*! * @enum os_activity_flag_t * * @discussion * Support flags for os_activity_create or os_activity_start. * * @constant OS_ACTIVITY_FLAG_DEFAULT * Use the default flags. * * @constant OS_ACTIVITY_FLAG_DETACHED * Detach the newly created activity from the provided activity (if any). If passed in conjunction * with an exiting activity, the activity will only note what activity "created" the new one, but * will make the new activity a top level activity. This allows users to see what activity triggered * work without actually relating the activities. * * @constant OS_ACTIVITY_FLAG_IF_NONE_PRESENT * Will only create a new activity if none present. If an activity ID is already present, a new object * will be returned with the same activity ID underneath. */ OS_ENUM(os_activity_flag, uint32_t, OS_ACTIVITY_FLAG_DEFAULT = 0, OS_ACTIVITY_FLAG_DETACHED = 0x1, OS_ACTIVITY_FLAG_IF_NONE_PRESENT = 0x2 ); #if OS_ACTIVITY_OBJECT_API #define OS_ACTIVITY_NULL NULL /*! * @typedef os_activity_t * An opaque activity object. */ __API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) #if OS_OBJECT_USE_OBJC OS_OBJECT_DECL(os_activity); #else typedef struct os_activity_s *os_activity_t; #endif /* OS_OBJECT_USE_OBJC */ /*! * @const OS_ACTIVITY_NONE * * @discussion * Create activity with no current traits, this is the equivalent of a * detached activity. */ #define OS_ACTIVITY_NONE OS_OBJECT_GLOBAL_OBJECT(os_activity_t, _os_activity_none) __API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) OS_EXPORT const struct os_activity_s _os_activity_none; /*! * @const OS_ACTIVITY_CURRENT * * @discussion * Create activity and links to the current activity if one is present. * If no activity is present it is treated as if it is detached. */ #define OS_ACTIVITY_CURRENT OS_OBJECT_GLOBAL_OBJECT(os_activity_t, _os_activity_current) __API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) OS_EXPORT const struct os_activity_s _os_activity_current; #else // !OS_ACTIVITY_OBJECT_API #define OS_ACTIVITY_NULL 0 /*! * @typedef os_activity_t * An opaque activity identifier. */ __API_AVAILABLE(macosx(10.10), ios(8.0), watchos(2.0), tvos(9.0)) typedef uint64_t os_activity_t; #endif // OS_ACTIVITY_OBJECT_API /*! * @typedef os_activity_id_t * An value representing the activity ID assigned to an newly created activity. */ __API_AVAILABLE(macosx(10.10), ios(8.0), watchos(2.0), tvos(9.0)) typedef uint64_t os_activity_id_t; #if !defined(__TRACE_BUILDING_TRACE__) /*! * @typedef os_activity_scope_state_t * Structure that is populated by os_activity_scope_enter and restored using * os_activity_scope_leave. */ __API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) typedef struct os_activity_scope_state_s { uint64_t opaque[2]; } *os_activity_scope_state_t; #else typedef struct os_activity_scope_state_s *os_activity_scope_state_t; #endif #pragma mark - Internal support functions #if OS_ACTIVITY_OBJECT_API __API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) OS_EXPORT OS_NOTHROW OS_WARN_RESULT_NEEDS_RELEASE OS_NOT_TAIL_CALLED OS_OBJECT_RETURNS_RETAINED os_activity_t _os_activity_create(void *dso, const char *description, os_activity_t activity, os_activity_flag_t flags); #endif /*! * @function _os_activity_label_useraction * * @abstract * Internal function for use by os_activity_label_useraction. Do not use directly. */ __API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) OS_EXPORT OS_NOTHROW OS_NOT_TAIL_CALLED void _os_activity_label_useraction(void *dso, const char *name); /*! * @function _os_activity_initiate * * @abstract * Do not use directly because your description will not be preserved. */ __API_AVAILABLE(macosx(10.10), ios(8.0), watchos(2.0), tvos(9.0)) OS_EXPORT OS_NOTHROW OS_NOT_TAIL_CALLED void _os_activity_initiate(void *dso, const char *description, os_activity_flag_t flags, os_block_t activity_block OS_NOESCAPE); /*! * @function _os_activity_initiate_f * * @abstract * Do not use directly because your description will not be preserved. */ __API_AVAILABLE(macosx(10.10), ios(8.0), watchos(2.0), tvos(9.0)) OS_EXPORT OS_NOTHROW OS_NOT_TAIL_CALLED void _os_activity_initiate_f(void *dso, const char *description, os_activity_flag_t flags, void *context, os_function_t function); #pragma mark - Internal deprecated function support /*! * @function _os_activity_set_breadcrumb * * @abstract * Internal function for setting breadcrumb. Do not use directly. */ __API_DEPRECATED_WITH_REPLACEMENT("os_activity_label_useraction", macosx(10.10, 10.12), ios(8.0, 10.0), watchos(2.0, 3.0), tvos(9.0, 10.0)) OS_EXPORT OS_NOTHROW OS_NOT_TAIL_CALLED void _os_activity_set_breadcrumb(void *dso, const char *name); /*! * @function _os_activity_start * * @abstract * Internal function for activity start, do not use directly will not preserve * description. */ __API_DEPRECATED("use combination of os_activity_create and os_activity_apply/os_activity_scope", macosx(10.10, 10.12), ios(8.0, 10.0), watchos(2.0, 3.0), tvos(9.0, 10.0)) OS_EXPORT OS_NOTHROW OS_WARN_RESULT OS_NOT_TAIL_CALLED os_activity_t _os_activity_start(void *dso, const char *description, os_activity_flag_t flags); #pragma mark - activity related /*! * @function os_activity_initiate * * @abstract * Synchronously initiates an activity using provided block. * * @discussion * Synchronously initiates an activity using the provided block and creates * a tracing buffer as appropriate. All new activities are created as a * subactivity of an existing activity on the current thread. * * os_activity_initiate("indexing database", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { * // either do work directly or issue work asynchronously * }); * * @param description * A constant string describing the activity, e.g., "performClick" or * "menuSelection". * * @param flags * Flags to be used when initiating the activity, typically OS_ACTIVITY_FLAG_DEFAULT. * * @param activity_block * The block to execute a given activity */ #define os_activity_initiate(description, flags, activity_block) __extension__({ \ OS_LOG_STRING(__description, description); \ _os_activity_initiate(&__dso_handle, __description, flags, activity_block); \ }) /*! * @function os_activity_initiate_f * * @abstract * Synchronously initiates an activity using the provided function. * * @discussion * Synchronously initiates an activity using the provided function and creates * a tracing buffer as appropriate. All new activities are created as a * subactivity of an existing activity on the current thread. * * os_activity_initiate_f("indexing database", OS_ACTIVITY_FLAG_DEFAULT, context, function); * * @param description * A constant string describing the activity, e.g., "performClick" or * "menuSelection". * * @param flags * Flags to be used when initiating the activity, typically OS_ACTIVITY_FLAG_DEFAULT. * * @param context * An optional context that will be supplied to the activity function. * * @param activity_func * The function to execute for the new activity. */ #define os_activity_initiate_f(description, flags, context, function) __extension__({ \ OS_LOG_STRING(__description, description); \ _os_activity_initiate_f(&__dso_handle, __description, flags, context, function); \ }) #if OS_ACTIVITY_OBJECT_API /*! * @function os_activity_create * * @abstract * Creates an os_activity_t object which can be passed to os_activity_apply function. * * @discussion * Creates an os_activity_t object which can be passed to os_activity_apply function. * * @param description * Pass a description for the activity. The description must be a constant string * within the calling executable or library. * * @param parent_activity * Depending on flags will link the newly created activity to the value passed or * note where the activity was created. Possible activities include: OS_ACTIVITY_NONE, * OS_ACTIVITY_CURRENT or any existing os_activity_t object created using os_activity_create. * * @param flags * A valid os_activity_flag_t which will determine behavior of the newly created activity. * * @result * Returns an os_activity_t object which can be used with os_activity_apply. */ #define os_activity_create(description, parent_activity, flags) __extension__({ \ OS_LOG_STRING(__description, description); \ os_activity_t __activity = _os_activity_create(&__dso_handle, __description, parent_activity, flags); \ __activity; \ }) /*! * @function os_activity_apply * * @abstract * Execute a block using a given activity object. * * @discussion * Execute a block using a given activity object. * * @param activity * There are global objects available which include: OS_ACTIVITY_NONE, OS_ACTIVITY_CURRENT * or an existing os_activity_t object. * * @param block * Pass the block to be executed within the context of the given activity. */ __API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) OS_EXPORT OS_NOTHROW void os_activity_apply(os_activity_t activity, os_block_t block OS_NOESCAPE); /*! * @function os_activity_apply_f * * @abstract * Execute a given function with a provided activity. * * @discussion * Execute a given function with a provided activity. * * @param activity * There are global objects available which include: OS_ACTIVITY_NONE, OS_ACTIVITY_CURRENT * or an existing os_activity_t object. * * @param context * Context to pass to the function which may be NULL. * * @param function * Pass the function to be executed within the context of the given activity. */ __API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) OS_EXPORT OS_NOTHROW void os_activity_apply_f(os_activity_t activity, void *context, os_function_t function); /*! * @function os_activity_scope_enter * * @abstract * Will change the current execution context to use the provided activity. * * @discussion * Will change the current execution context to use the provided activity. An activity * can be created and then applied to the current scope by doing: * * struct os_activity_scope_state_s state; * os_activity_t activity = os_activity_create("my new activity", 0); * os_activity_scope_enter(activity, &state); * ... do some work ... * os_activity_scope_leave(&state); * * To auto-cleanup state call: * * os_activity_scope(activity); * * @param activity * Pass a valid activity created with os_activity_create or any global object. * * @param state * A stack-based struct os_activity_scope_state_s to store the state. */ __API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) OS_EXPORT OS_NOTHROW void os_activity_scope_enter(os_activity_t activity, os_activity_scope_state_t state); /*! * @function os_activity_scope_leave * * @abstract * Will pop state up to the state provided. * * @discussion * Will leave scope using the state provided. If state is not present an error will be * generated. * * @param state * Must be a valid value filled by os_activity_scope_enter call. */ __API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) OS_EXPORT OS_NOTHROW void os_activity_scope_leave(os_activity_scope_state_t state); #if defined(__GNUC__) #define _os_activity_scope(var, activity) \ struct os_activity_scope_state_s var __attribute__((__cleanup__(os_activity_scope_leave))); \ os_activity_scope_enter(activity, &var) #define os_activity_scope(activity) _os_activity_scope(OS_CONCAT(scope, __COUNTER__), activity) #endif #endif // OS_ACTIVITY_OBJECT_API /*! * @function os_activity_start * * @abstract * Starts a new activity immediately within the current context. * * @discussion * Starts a new activity immediately within the current context. Deprecated please use new * os_activity_create and os_activity_apply. * * os_activity_t activity = os_activity_start("indexing database", OS_ACTIVITY_FLAG_DEFAULT); * < do some work > * os_activity_end(activity); * * @param description * A constant string describing the activity, e.g., "performClick" or * "menuSelection". * * @param flags * Flags to be used when initiating the activity, typically OS_ACTIVITY_FLAG_DEFAULT. * * @result * Returns a valid os_activity_id_t or 0 on failure. */ #define os_activity_start(description, flags) __extension__({ \ OS_LOG_STRING(__description, description); \ os_activity_t _aid = _os_activity_start(&__dso_handle, __description, flags); \ _aid; \ }) /*! * @function os_activity_end * * @abstract * Ends the specified activity on the current thread. * * @discussion * Ends the specified activity on the current thread. Does not signify anything * other than the originator has received control back from the activity. Work * could still be in flight related to the activity. * * @param activity * An os_activity_t returned from os_activity_start. */ __API_DEPRECATED("use combination of os_activity_create and os_activity_apply/os_activity_scope", macosx(10.10, 10.12), ios(8.0, 10.0), watchos(2.0, 3.0), tvos(9.0, 10.0)) OS_EXPORT OS_NOTHROW void os_activity_end(os_activity_t activity); /*! * @function os_activity_get_active * * @abstract * Returns the stack of nested activities associated with the current thread. * * @discussion * Activities have a sense of nesting and therefore there could be more than * one activity involved on the current thread. This should be used by * diagnostic tools only for making additional decisions about a situation. * * @param entries * Pass a buffer of sufficient size to hold the the number of os_activity_id_t * being requested. * * @param count * Pointer to the requested number of activity identifiers. * On output will be filled with the number of activities that are available. * * @result * Number of activity identifiers written to 'entries' */ __API_DEPRECATED("No longer supported", macosx(10.10, 10.12), ios(8.0, 10.0), watchos(2.0, 3.0), tvos(9.0, 10.0)) OS_EXPORT OS_NOTHROW unsigned int os_activity_get_active(os_activity_id_t *entries, unsigned int *count); /*! * @function os_activity_get_identifier * * @abstract * Returns the current activity ID and will fill the parent_id if present. * * @discussion * Returns the current activity ID and will fill the parent_id if present. * * @param parent_id * If non-null will set the parent activity ID. * * @result * The identifier for the provided activity. */ __API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) OS_EXPORT OS_NOTHROW OS_NONNULL1 OS_WARN_RESULT os_activity_id_t os_activity_get_identifier(os_activity_t activity, os_activity_id_t *parent_id); /*! * @function os_activity_label_useraction * * @abstract * Label an activity that is auto-generated by AppKit/UIKit with a name that is useful * for debugging macro-level user actions. * * @discussion * Label an activity that is auto-generated by AppKit/UIKit with a name that is useful * for debugging macro-level user actions. The API should be called early within the scope * of the IBAction and before any sub-activities are created. The name provided will * be shown in tools in additon to the underlying AppKit/UIKit provided name. This API * can only be called once and only on the activity created by AppKit/UIKit. These actions * help determine workflow of the user in order to reproduce problems that occur. * For example, a control press and/or menu item selection can be labeled: * * os_activity_label_useraction("New mail message"); * os_activity_label_useraction("Empty trash"); * * Where the underlying AppKit/UIKit name will be "gesture:" or "menuSelect:". * * @param name * A constant string that describes the the action. */ #define os_activity_label_useraction(label) __extension__({ \ OS_LOG_STRING(__label, label); \ _os_activity_label_useraction(&__dso_handle, __label); \ }) #pragma mark - application breadcrumbs /*! * @function os_activity_set_breadcrumb * * @abstract * This flags the current activity as a "breadcrumb", i.e., an interesting event. * * @discussion * Not all activities are interesting events at the macro-level. Some activities * can be flagged as a breadcrumb for evalutating cross activity interactions. * This can only be called once per activity, other requests will be ignored. * * @param name * A constant string that describes the breadcrumb. */ #define os_activity_set_breadcrumb(name) __extension__({ \ OS_LOG_STRING(__name, name); \ _os_activity_set_breadcrumb(&__dso_handle, __name); \ }) __END_DECLS #endif // __OS_ACTIVITY_H__