1/*
2 * Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30/*  Sample thread data */
31
32#include <mach/mach_types.h>
33#include <kern/thread.h> /* thread_* */
34#include <kern/debug.h> /* panic */
35// #include <sys/proc.h>
36
37#include <chud/chud_xnu.h>
38#include <kperf/kperf.h>
39
40#include <kperf/buffer.h>
41#include <kperf/context.h>
42#include <kperf/threadinfo.h>
43#include <kperf/ast.h>
44
45// kAppleProfileTriggerClientThreadModeIdle				= 0x40, // TH_IDLE
46// #define TH_IDLE 0x40
47
48//kAppleProfileTriggerClientThreadModeNotIdle				= kAppleProfileTriggerClientThreadModeIdle << 16, // !TH_IDLE
49#define TH_IDLE_N (TH_IDLE << 16)
50
51static uint64_t
52make_runmode(thread_t thread)
53{
54	/* CEG: This is a translation of
55	 * AppleProfileGetRunModeOfThread below... kinda magic :/
56	 */
57	const int mode = chudxnu_thread_get_scheduler_state(thread);
58
59	if( 0 == mode)
60	{
61		return (chudxnu_thread_get_idle(thread) ? TH_IDLE : TH_IDLE_N);
62	}
63	else
64	{
65		// Today we happen to know there's a one-to-one mapping.
66		return ((mode & 0xffff) | ((~mode & 0xffff) << 16));
67	}
68}
69
70
71/* code to collect current thread info */
72void
73kperf_threadinfo_sample(struct threadinfo *ti, struct kperf_context *context)
74{
75	thread_t cur_thread = context->cur_thread;
76	BUF_INFO1( PERF_TI_SAMPLE, (uintptr_t)cur_thread );
77
78	// fill out the fields
79	ti->pid = context->cur_pid;
80	ti->tid = thread_tid(cur_thread);
81	ti->dq_addr = thread_dispatchqaddr(cur_thread);
82	ti->runmode = make_runmode(cur_thread);
83}
84
85/* log an existing sample into the buffer */
86void
87kperf_threadinfo_log(struct threadinfo *ti)
88{
89	/* XXX: K64 only? */
90	BUF_DATA( PERF_TI_DATA, ti->pid, ti->tid, ti->dq_addr, ti->runmode );
91}
92
93/* 'extra' thread-info functions that are deferred 'til thread-context
94 * time
95 */
96void
97kperf_threadinfo_extra_sample(struct tinfo_ex *tex, struct kperf_context *context)
98{
99	thread_t cur_thread = context->cur_thread;
100	uint32_t t_chud;
101
102	/* can only pend on the current thread */
103	/* this is valid from PET mode... */
104	/*
105	if( cur_thread != chudxnu_current_thread() )
106		panic("pending to non-current thread");
107	*/
108
109	/* get our current bits */
110	t_chud = kperf_get_thread_bits(cur_thread);
111
112	/* check if there's anything for us to do */
113	if( t_chud & T_AST_NAME )
114	{
115		BUF_INFO1( PERF_TI_XSAMPLE, (uintptr_t)cur_thread );
116
117		/* get the name out */
118#ifdef FIXME
119		/* need kperfbsd.c? */
120		proc_name( context->cur_pid,
121		           &tex->p_comm[0], CHUD_MAXPCOMM );
122#endif
123
124		/* mark that it's done */
125		t_chud &= ~T_AST_NAME;
126		t_chud |= T_NAME_DONE;
127
128		kperf_set_thread_bits(cur_thread, t_chud);
129	}
130	else
131		/* empty string */
132		tex->p_comm[0] = '\0';
133
134}
135
136/* log it if there's anyting useful there */
137void
138kperf_threadinfo_extra_log(struct tinfo_ex *tex)
139{
140	/* no data */
141	if( tex->p_comm[0] == '\0' )
142		return;
143
144	/* FIXME: log more */
145	BUF_DATA1( PERF_TI_XDATA, (uintptr_t)*(uintptr_t*)&tex->p_comm[0] );
146}
147
148/* pend a flag on a thread */
149int
150kperf_threadinfo_extra_pend(struct kperf_context *context)
151{
152	return kperf_ast_pend( context->cur_thread, T_NAME_DONE | T_AST_NAME,
153	                       T_AST_NAME );
154}
155
156
157#if 0
158
159/* transalted from the APF */
160
161APTIAKernelEntry_t *threadInfo = (APTIAKernelEntry_t*)(threadInfos + account->offset);
162
163context->timeStamp = mach_absolute_time();
164context->cpuNum = chudxnu_cpu_number();
165
166// record the process info from the callback context
167context->pid = chudxnu_current_pid();
168threadInfo->pid = context->generic->pid;
169
170// thread_tid is a thread_t to ID function in the kernel
171context->threadID = chudxnu_current_thread();
172threadInfo->tid = thread_tid(context->generic->threadID);
173
174// also a kernel function
175threadInfo->dispatch_queue_addr = thread_dispatchqaddr(context->generic->threadID);
176
177// see below
178threadInfo->runMode = AppleProfileGetRunModeOfThread(context->generic->threadID);
179
180
181/****** WTF is this?! *******/
182
183/*!enum AppleProfileTriggerClientThreadRunMode
184 *
185 * Specifies the thread mode in which to record samples.
186 */
187typedef enum { // Target Thread State - can be OR'd
188	// Basic Building Blocks:
189	// for Time Profile, use kAppleProfileTriggerClientThreadModeRunning (optionally with kAppleProfileTriggerClientThreadModeNotIdle).
190	// for Time Profile (All Thread States), use kAppleProfileTriggerClientThreadModeAny (or just don't specify any thread mode filters).
191	// for Time Profile (Blocked Threads), use kIOProfileTriggerClientThreadModeBlocked.
192	// etc...
193
194	kAppleProfileTriggerClientThreadModeNone				= 0x0,
195
196	kAppleProfileTriggerClientThreadModeRunning				= 0x1, // On a core
197	kAppleProfileTriggerClientThreadModeRunnable			= 0x2, // TH_RUN
198	kAppleProfileTriggerClientThreadModeBlocked				= 0x4, // TH_WAIT
199	kAppleProfileTriggerClientThreadModeUninterruptible		= 0x8, // TH_UNINT
200	kAppleProfileTriggerClientThreadModeSuspended			= 0x10, // TH_SUSP
201	kAppleProfileTriggerClientThreadModeTerminating			= 0x20, // TH_TERMINATE
202	kAppleProfileTriggerClientThreadModeIdle				= 0x40, // TH_IDLE
203
204	kAppleProfileTriggerClientThreadModeNotRunning			= kAppleProfileTriggerClientThreadModeRunning << 16, // Not on a core
205	kAppleProfileTriggerClientThreadModeNotRunnable			= kAppleProfileTriggerClientThreadModeRunnable << 16, // !TH_RUN
206	kAppleProfileTriggerClientThreadModeNotBlocked			= kAppleProfileTriggerClientThreadModeBlocked << 16, // !TH_WAIT
207	kAppleProfileTriggerClientThreadModeNotUninterruptible	= kAppleProfileTriggerClientThreadModeUninterruptible << 16, // !TH_UNINT
208	kAppleProfileTriggerClientThreadModeNotSuspended		= kAppleProfileTriggerClientThreadModeSuspended << 16, // !TH_SUSP
209	kAppleProfileTriggerClientThreadModeNotTerminating		= kAppleProfileTriggerClientThreadModeTerminating << 16, // !TH_TERMINATE
210	kAppleProfileTriggerClientThreadModeNotIdle				= kAppleProfileTriggerClientThreadModeIdle << 16, // !TH_IDLE
211
212	kAppleProfileTriggerClientThreadModeAny					= (   kAppleProfileTriggerClientThreadModeRunning
213																| kAppleProfileTriggerClientThreadModeNotRunning),
214} AppleProfileTriggerClientThreadRunMode;
215
216extern "C" AppleProfileTriggerClientThreadRunMode AppleProfileGetRunModeOfThread(thread_t thread) {
217	const int mode = chudxnu_thread_get_scheduler_state(thread);
218
219	if (0 == mode) {
220		return (chudxnu_thread_get_idle(thread) ? kAppleProfileTriggerClientThreadModeIdle : kAppleProfileTriggerClientThreadModeNotIdle);
221	} else
222	return (AppleProfileTriggerClientThreadRunMode)((mode & 0xffff) | ((~mode & 0xffff) << 16)); // Today we happen to know there's a one-to-one mapping.
223}
224
225#endif
226