voucher_activity_private.h   [plain text]


/*
 * Copyright (c) 2013-2014 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 *
 * Licensed 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.
 *
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

#ifndef __OS_VOUCHER_ACTIVITY_PRIVATE__
#define __OS_VOUCHER_ACTIVITY_PRIVATE__

#include <os/base.h>
#include <os/object.h>
#if !defined(__DISPATCH_BUILDING_DISPATCH__)
#include <os/voucher_private.h>
#endif

#define OS_VOUCHER_ACTIVITY_SPI_VERSION 20150318

#if OS_VOUCHER_WEAK_IMPORT
#define OS_VOUCHER_EXPORT OS_EXPORT OS_WEAK_IMPORT
#else
#define OS_VOUCHER_EXPORT OS_EXPORT
#endif

__BEGIN_DECLS

#if OS_VOUCHER_ACTIVITY_SPI

/*!
 * @group Voucher Activity SPI
 * SPI intended for libtrace only
 */

/*!
 * @typedef voucher_activity_id_t
 *
 * @abstract
 * Opaque activity identifier.
 *
 * @discussion
 * Scalar value type, not reference counted.
 */
typedef uint64_t voucher_activity_id_t;

/*!
 * @enum voucher_activity_tracepoint_type_t
 *
 * @abstract
 * Types of tracepoints.
 */
OS_ENUM(voucher_activity_tracepoint_type, uint8_t,
	voucher_activity_tracepoint_type_release = (1u << 0),
	voucher_activity_tracepoint_type_debug = (1u << 1),
	voucher_activity_tracepoint_type_error = (1u << 6) | (1u << 0),
	voucher_activity_tracepoint_type_fault = (1u << 7) | (1u << 6) | (1u << 0),
);

/*!
 * @enum voucher_activity_flag_t
 *
 * @abstract
 * Flags to pass to voucher_activity_start/voucher_activity_start_with_location
 */
OS_ENUM(voucher_activity_flag, unsigned long,
	voucher_activity_flag_default = 0,
	voucher_activity_flag_force = 0x1,
	voucher_activity_flag_debug = 0x2,
	voucher_activity_flag_persist = 0x4,
	voucher_activity_flag_stream = 0x8,
);

/*!
 * @typedef voucher_activity_trace_id_t
 *
 * @abstract
 * Opaque tracepoint identifier.
 */
typedef uint64_t voucher_activity_trace_id_t;
static const uint8_t _voucher_activity_trace_id_type_shift = 40;
static const uint8_t _voucher_activity_trace_id_code_namespace_shift = 32;

/*!
 * @function voucher_activity_trace_id
 *
 * @abstract
 * Return tracepoint identifier for specified arguments.
 *
 * @param type
 * Tracepoint type from voucher_activity_tracepoint_type_t.
 *
 * @param code_namespace
 * Namespace of 'code' argument.
 *
 * @param code
 * Tracepoint code.
 *
 * @result
 * Tracepoint identifier.
 */
__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
OS_INLINE OS_ALWAYS_INLINE
voucher_activity_trace_id_t
voucher_activity_trace_id(uint8_t type, uint8_t code_namespace, uint32_t code)
{
	return ((voucher_activity_trace_id_t)type <<
			_voucher_activity_trace_id_type_shift) |
			((voucher_activity_trace_id_t)code_namespace <<
			_voucher_activity_trace_id_code_namespace_shift) |
			(voucher_activity_trace_id_t)code;
}

/*!
 * @function voucher_activity_start
 *
 * @abstract
 * Creates a new activity identifier and marks the current thread as
 * participating in the activity.
 *
 * @discussion
 * As part of voucher transport, activities are automatically propagated by the
 * system to other threads and processes (across IPC).
 *
 * Activities persist as long as any threads in any process are marked as
 * participating. There may be many calls to voucher_activity_end()
 * corresponding to one call to voucher_activity_start().
 *
 * @param trace_id
 * Tracepoint identifier returned by voucher_activity_trace_id(), intended for
 * identification of the automatic tracepoint generated as part of creating the
 * new activity.
 *
 * @param flags
 * Pass voucher_activity_flag_force to indicate that existing activities
 * on the current thread should not be inherited and that a new toplevel
 * activity should be created.
 *
 * @result
 * A new activity identifier.
 */
__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
OS_VOUCHER_EXPORT OS_WARN_RESULT OS_NOTHROW
voucher_activity_id_t
voucher_activity_start(voucher_activity_trace_id_t trace_id,
		voucher_activity_flag_t flags);

/*!
 * @function voucher_activity_start_with_location
 *
 * @abstract
 * Creates a new activity identifier and marks the current thread as
 * participating in the activity.
 *
 * @discussion
 * As part of voucher transport, activities are automatically propagated by the
 * system to other threads and processes (across IPC).
 *
 * Activities persist as long as any threads in any process are marked as
 * participating. There may be many calls to voucher_activity_end()
 * corresponding to one call to voucher_activity_start_with_location().
 *
 * @param trace_id
 * Tracepoint identifier returned by voucher_activity_trace_id(), intended for
 * identification of the automatic tracepoint generated as part of creating the
 * new activity.
 *
 * @param location
 * Location identifier for the automatic tracepoint generated as part of
 * creating the new activity.
 *
 * @param flags
 * Pass voucher_activity_flag_force to indicate that existing activities
 * on the current thread should not be inherited and that a new toplevel
 * activity should be created.
 *
 * @result
 * A new activity identifier.
 */
__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
OS_VOUCHER_EXPORT OS_WARN_RESULT OS_NOTHROW
voucher_activity_id_t
voucher_activity_start_with_location(voucher_activity_trace_id_t trace_id,
		uint64_t location, voucher_activity_flag_t flags);

/*!
 * @function voucher_activity_end
 *
 * @abstract
 * Unmarks the current thread if it is marked as particpating in the activity
 * with the specified identifier.
 *
 * @discussion
 * Activities persist as long as any threads in any process are marked as
 * participating. There may be many calls to voucher_activity_end()
 * corresponding to one call to voucher_activity_start() or
 * voucher_activity_start_with_location().
 */
__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
OS_VOUCHER_EXPORT OS_NOTHROW
void
voucher_activity_end(voucher_activity_id_t activity_id);

/*!
 * @function voucher_get_activities
 *
 * @abstract
 * Returns the list of activity identifiers that the current thread is marked
 * with.
 *
 * @param entries
 * Pointer to an array of activity identifiers to be filled in.
 *
 * @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'
 */
__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
OS_VOUCHER_EXPORT OS_NOTHROW
unsigned int
voucher_get_activities(voucher_activity_id_t *entries, unsigned int *count);

/*!
 * @group Voucher Activity Trace SPI
 * SPI intended for libtrace only
 */

/*!
 * @function voucher_activity_get_namespace
 *
 * @abstract
 * Returns the namespace of the current activity.
 *
 * @result
 * The namespace of the current activity (if any).
 */
__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
OS_VOUCHER_EXPORT OS_NOTHROW
uint8_t
voucher_activity_get_namespace(void);

/*!
 * @function voucher_activity_trace
 *
 * @abstract
 * Add a tracepoint to trace buffer of the current activity.
 *
 * @param trace_id
 * Tracepoint identifier returned by voucher_activity_trace_id()
 *
 * @param location
 * Tracepoint location.
 *
 * @param buffer
 * Pointer to packed buffer of tracepoint data.
 *
 * @param length
 * Length of data at 'buffer'.
 *
 * @result
 * Timestamp recorded in tracepoint or 0 if no tracepoint was recorded.
 */
__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
OS_VOUCHER_EXPORT OS_NOTHROW
uint64_t
voucher_activity_trace(voucher_activity_trace_id_t trace_id, uint64_t location,
		void *buffer, size_t length);

/*!
 * @function voucher_activity_trace_strings
 *
 * @abstract
 * Add a tracepoint with strings data to trace buffer of the current activity.
 *
 * @param trace_id
 * Tracepoint identifier returned by voucher_activity_trace_id()
 *
 * @param location
 * Tracepoint location.
 *
 * @param buffer
 * Pointer to packed buffer of tracepoint data.
 *
 * @param length
 * Length of data at 'buffer'.
 *
 * @param strings
 * NULL-terminated array of strings data.
 *
 * @param string_lengths
 * Array of string lengths (required to have the same number of elements as the
 * 'strings' array): string_lengths[i] is the maximum number of characters to
 * copy from strings[i], excluding the NUL-terminator (may be smaller than the
 * length of the string present in strings[i]).
 *
 * @param total_strings_size
 * Total size of all strings data to be copied from strings array (including
 * all NUL-terminators).
 *
 * @result
 * Timestamp recorded in tracepoint or 0 if no tracepoint was recorded.
 */
__OSX_AVAILABLE_STARTING(__MAC_10_11,__IPHONE_9_0)
OS_VOUCHER_EXPORT OS_NOTHROW
uint64_t
voucher_activity_trace_strings(voucher_activity_trace_id_t trace_id,
		uint64_t location, void *buffer, size_t length, const char *strings[],
		size_t string_lengths[], size_t total_strings_size);

/*!
 * @function voucher_activity_trace_args
 *
 * @abstract
 * Add a tracepoint to trace buffer of the current activity, recording
 * specified arguments passed in registers.
 *
 * @param trace_id
 * Tracepoint identifier returned by voucher_activity_trace_id()
 *
 * @param location
 * Tracepoint location.
 *
 * @param arg1
 * Argument to be recorded in tracepoint data.
 *
 * @param arg2
 * Argument to be recorded in tracepoint data.
 *
 * @param arg3
 * Argument to be recorded in tracepoint data.
 *
 * @param arg4
 * Argument to be recorded in tracepoint data.
 *
 * @result
 * Timestamp recorded in tracepoint or 0 if no tracepoint was recorded.
 */
__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
OS_VOUCHER_EXPORT OS_NOTHROW
uint64_t
voucher_activity_trace_args(voucher_activity_trace_id_t trace_id,
		uint64_t location, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
		uintptr_t arg4);

/*!
 * @group Voucher Activity Mode SPI
 * SPI intended for libtrace only
 */

/*!
 * @enum voucher_activity_mode_t
 *
 * @abstract
 * Voucher activity mode.
 *
 * @discussion
 * Configure at process start by setting the OS_ACTIVITY_MODE environment
 * variable.
 */
OS_ENUM(voucher_activity_mode, unsigned long,
	voucher_activity_mode_disable = 0,
	voucher_activity_mode_release = (1u << 0),
	voucher_activity_mode_debug = (1u << 1),
	voucher_activity_mode_stream = (1u << 2),
);

/*!
 * @function voucher_activity_get_mode
 *
 * @abstract
 * Return current mode of voucher activity subsystem.
 *
 * @result
 * Value from voucher_activity_mode_t enum.
 */
__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
OS_VOUCHER_EXPORT OS_WARN_RESULT OS_NOTHROW
voucher_activity_mode_t
voucher_activity_get_mode(void);

/*!
 * @function voucher_activity_set_mode_4libtrace
 *
 * @abstract
 * Set the current mode of voucher activity subsystem.
 *
 * @param mode
 * The new mode.
 *
 * Note that the new mode will take effect soon, but not immediately.
 */
__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
OS_VOUCHER_EXPORT OS_NOTHROW
void
voucher_activity_set_mode_4libtrace(voucher_activity_mode_t mode);

/*!
 * @group Voucher Activity Metadata SPI
 * SPI intended for libtrace only
 */

/*!
 * @function voucher_activity_get_metadata_buffer
 *
 * @abstract
 * Return address and length of buffer in the process trace memory area
 * reserved for libtrace metadata.
 *
 * @param length
 * Pointer to size_t variable, filled with length of metadata buffer.
 *
 * @result
 * Address of metadata buffer.
 */
__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
OS_VOUCHER_EXPORT OS_WARN_RESULT OS_NOTHROW OS_NONNULL_ALL
void*
voucher_activity_get_metadata_buffer(size_t *length);

#endif // OS_VOUCHER_ACTIVITY_SPI

#if OS_VOUCHER_ACTIVITY_BUFFER_SPI

/*!
 * @group Voucher Activity Tracepoint SPI
 * SPI intended for diagnosticd only
 */

OS_ENUM(_voucher_activity_tracepoint_flag, uint16_t,
	_voucher_activity_trace_flag_buffer_empty = 0,
	_voucher_activity_trace_flag_tracepoint = (1u << 0),
	_voucher_activity_trace_flag_tracepoint_args = (1u << 1),
	_voucher_activity_trace_flag_tracepoint_strings = (1u << 2),
	_voucher_activity_trace_flag_wide_first = (1u << 6),
	_voucher_activity_trace_flag_wide_second = (1u << 6) | (1u << 7),
	_voucher_activity_trace_flag_start = (1u << 8),
	_voucher_activity_trace_flag_end = (1u << 8) | (1u << 9),
	_voucher_activity_trace_flag_libdispatch = (1u << 13),
	_voucher_activity_trace_flag_activity = (1u << 14),
	_voucher_activity_trace_flag_buffer_header = (1u << 15),
);

// for tracepoints with _voucher_activity_trace_flag_libdispatch
OS_ENUM(_voucher_activity_tracepoint_namespace, uint8_t,
	_voucher_activity_tracepoint_namespace_ipc = 0x1
);
OS_ENUM(_voucher_activity_tracepoint_code, uint32_t,
	_voucher_activity_tracepoint_namespace_ipc_send = 0x1,
	_voucher_activity_tracepoint_namespace_ipc_receive = 0x2,
);

typedef struct _voucher_activity_tracepoint_s {
	uint16_t vat_flags;		// voucher_activity_tracepoint_flag_t
	uint8_t  vat_type;		// voucher_activity_tracepoint_type_t
	uint8_t  vat_namespace;	// namespace for tracepoint code
	uint32_t vat_code;		// tracepoint code
	uint64_t vat_thread;	// pthread_t
	uint64_t vat_timestamp;	// absolute time
	uint64_t vat_location;	// tracepoint PC
	union {
		uint64_t vat_data[4];	// trace data
		struct {
			uint16_t vats_offset;	// offset to string data (from buffer end)
			uint8_t vats_data[30];	// trace data
		} vat_stroff;				// iff _vat_flag_tracepoint_strings present
	};
} *_voucher_activity_tracepoint_t;

/*!
 * @group Voucher Activity Buffer Internals
 * SPI intended for diagnosticd only
 * Layout of structs is subject to change without notice
 */

#include <sys/queue.h>
#include <atm/atm_types.h>
#include <os/lock_private.h>

static const size_t _voucher_activity_buffer_size = 4096;
static const size_t _voucher_activity_tracepoints_per_buffer =
		_voucher_activity_buffer_size /
		sizeof(struct _voucher_activity_tracepoint_s);
static const size_t _voucher_activity_buffer_header_size =
		sizeof(struct _voucher_activity_tracepoint_s);
static const size_t _voucher_activity_strings_header_size = 0; // TODO

typedef uint8_t _voucher_activity_buffer_t[_voucher_activity_buffer_size];

static const size_t _voucher_activity_buffers_per_heap = 512;
typedef unsigned long _voucher_activity_bitmap_base_t;
static const size_t _voucher_activity_bits_per_bitmap_base_t =
		8 * sizeof(_voucher_activity_bitmap_base_t);
static const size_t _voucher_activity_bitmaps_per_heap =
		_voucher_activity_buffers_per_heap /
		_voucher_activity_bits_per_bitmap_base_t;
typedef _voucher_activity_bitmap_base_t
		_voucher_activity_bitmap_t[_voucher_activity_bitmaps_per_heap]
		__attribute__((__aligned__(64)));

struct _voucher_activity_self_metadata_s {
	struct _voucher_activity_metadata_opaque_s *vasm_baseaddr;
	_voucher_activity_bitmap_t volatile vam_buffer_bitmap;
};

typedef struct _voucher_activity_metadata_opaque_s {
	_voucher_activity_buffer_t vam_client_metadata;
	union {
		struct _voucher_activity_self_metadata_s vam_self_metadata;
		_voucher_activity_buffer_t vam_self_metadata_opaque;
	};
} *_voucher_activity_metadata_opaque_t;

typedef os_lock_handoff_s _voucher_activity_lock_s;

OS_ENUM(_voucher_activity_buffer_atomic_flags, uint8_t,
	_voucher_activity_buffer_full = (1u << 0),
	_voucher_activity_buffer_pushing = (1u << 1),
);

typedef union {
	uint64_t vabp_atomic_pos;
	struct {
		uint16_t vabp_refcnt;
		uint8_t vabp_flags;
		uint8_t vabp_unused;
		uint16_t vabp_next_tracepoint_idx;
		uint16_t vabp_string_offset; // offset from the _end_ of the buffer
	} vabp_pos;
} _voucher_activity_buffer_position_u;

// must match layout of _voucher_activity_tracepoint_s
typedef struct _voucher_activity_buffer_header_s {
	uint16_t vabh_flags;	// _voucher_activity_trace_flag_buffer_header
	uint8_t  vat_type;
	uint8_t  vat_namespace;
	uint32_t vat_code;
	uint64_t vat_thread;
	uint64_t vat_timestamp;
	uint64_t vat_location;
	voucher_activity_id_t vabh_activity_id;
	_voucher_activity_buffer_position_u volatile vabh_pos;
	TAILQ_ENTRY(_voucher_activity_buffer_header_s) vabh_list;
} *_voucher_activity_buffer_header_t;

/*!
 * @enum _voucher_activity_buffer_hook_reason
 *
 * @constant _voucher_activity_buffer_hook_reason_full
 * Specified activity buffer is full.
 * Will be reported reused or freed later.
 *
 * @constant _voucher_activity_buffer_hook_reason_reuse
 * Specified activity buffer is about to be reused.
 * Was previously reported as full.
 *
 * @constant _voucher_activity_buffer_hook_reason_free
 * Specified activity buffer is about to be freed.
 * May have been previously reported as full or may be only partially filled.
 */
typedef enum _voucher_activity_buffer_hook_reason {
	_voucher_activity_buffer_hook_reason_full = 0x1,
	_voucher_activity_buffer_hook_reason_reuse = 0x2,
	_voucher_activity_buffer_hook_reason_free = 0x4,
} _voucher_activity_buffer_hook_reason;

/*!
 * @typedef _voucher_activity_buffer_hook_t
 *
 * @abstract
 * A function pointer called when an activity buffer is full or being freed.
 * NOTE: callbacks occur under an activity-wide handoff lock and work done
 * inside the callback function must not block or otherwise cause that lock to
 * be held for a extended period of time.
 *
 * @param reason
 * Reason for callback.
 *
 * @param buffer
 * Pointer to activity buffer.
 */
typedef void (*_voucher_activity_buffer_hook_t)(
		_voucher_activity_buffer_hook_reason reason,
		_voucher_activity_buffer_header_t buffer);

/*!
 * @function voucher_activity_buffer_hook_install_4libtrace
 *
 * @abstract
 * Install activity buffer hook callback function.
 * Must be called from the libtrace initializer, and at most once.
 *
 * @param hook
 * Hook function to install.
 */
__OSX_AVAILABLE_STARTING(__MAC_10_11,__IPHONE_9_0)
OS_VOUCHER_EXPORT OS_NOTHROW
void
voucher_activity_buffer_hook_install_4libtrace(
		_voucher_activity_buffer_hook_t hook);

#endif // OS_VOUCHER_ACTIVITY_BUFFER_SPI

__END_DECLS

#endif // __OS_VOUCHER_ACTIVITY_PRIVATE__