|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989 Carnegie Mellon University.
4: * Copyright (c) 1993,1994 The University of Utah and
5: * the Computer Systems Laboratory (CSL).
6: * All rights reserved.
7: *
8: * Permission to use, copy, modify and distribute this software and its
9: * documentation is hereby granted, provided that both the copyright
10: * notice and this permission notice appear in all copies of the
11: * software, derivative works or modified versions, and any portions
12: * thereof, and that both notices appear in supporting documentation.
13: *
14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
17: * THIS SOFTWARE.
18: *
19: * Carnegie Mellon requests users of this software to return to
20: *
21: * Software Distribution Coordinator or [email protected]
22: * School of Computer Science
23: * Carnegie Mellon University
24: * Pittsburgh PA 15213-3890
25: *
26: * any improvements or extensions that they make and grant Carnegie Mellon
27: * the rights to redistribute these changes.
28: */
29: /*
30: * Copyright 1991 by Open Software Foundation,
31: * Grenoble, FRANCE
32: *
33: * All Rights Reserved
34: *
35: * Permission to use, copy, modify, and distribute this software and
36: * its documentation for any purpose and without fee is hereby granted,
37: * provided that the above copyright notice appears in all copies and
38: * that both the copyright notice and this permission notice appear in
39: * supporting documentation, and that the name of OSF or Open Software
40: * Foundation not be used in advertising or publicity pertaining to
41: * distribution of the software without specific, written prior
42: * permission.
43: *
44: * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
45: * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
46: * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
47: * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
48: * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
49: * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
50: * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
51: */
52:
53: #if 0
54:
55: #include <kern/thread.h>
56: #include <kern/queue.h>
57: #include <mach/profil.h>
58: #include <kern/sched_prim.h>
59: #include <ipc/ipc_space.h>
60:
61: extern vm_map_t kernel_map; /* can be discarded, defined in <vm/vm_kern.h> */
62:
63: thread_t profile_thread_id = THREAD_NULL;
64:
65:
66: void profile_thread()
67: {
68: struct message {
69: mach_msg_header_t head;
70: mach_msg_type_t type;
71: int arg[SIZE_PROF_BUFFER+1];
72: } msg;
73:
74: register spl_t s;
75: buf_to_send_t buf_entry;
76: queue_entry_t prof_queue_entry;
77: prof_data_t pbuf;
78: simple_lock_t lock;
79: msg_return_t mr;
80: int j;
81:
82: /* Initialise the queue header for the prof_queue */
83: mpqueue_init(&prof_queue);
84:
85: /* Template initialisation of header and type structures */
86: msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
87: msg.head.msgh_size = sizeof(msg);
88: msg.head.msgh_local_port = MACH_PORT_NULL;
89: msg.head.msgh_kind = MACH_MSGH_KIND_NORMAL;
90: msg.head.msgh_id = 666666;
91:
92: msg.type.msgt_name = MACH_MSG_TYPE_INTEGER_32;
93: msg.type.msgt_size = 32;
94: msg.type.msgt_number = SIZE_PROF_BUFFER+1;
95: msg.type.msgt_inline = TRUE;
96: msg.type.msgt_longform = FALSE;
97: msg.type.msgt_deallocate = FALSE;
98: msg.type.msgt_unused = 0;
99:
100: while (TRUE) {
101:
102: /* Dequeue the first buffer. */
103: s = splsched();
104: mpdequeue_head(&prof_queue, &prof_queue_entry);
105: splx(s);
106:
107: if ((buf_entry = (buf_to_send_t) prof_queue_entry) == NULLBTS)
108: {
109: thread_sleep((event_t) profile_thread, lock, TRUE);
110: if (current_thread()->wait_result != THREAD_AWAKENED)
111: break;
112: }
113: else {
114: task_t curr_task;
115: thread_t curr_th;
116: register int *sample;
117: int curr_buf;
118: int imax;
119:
120: curr_th = (thread_t) buf_entry->thread;
121: curr_buf = (int) buf_entry->number;
122: pbuf = curr_th->profil_buffer;
123:
124: /* Set the remote port */
125: msg.head.msgh_remote_port = (mach_port_t) pbuf->prof_port;
126:
127:
128: sample = pbuf->prof_area[curr_buf].p_zone;
129: imax = pbuf->prof_area[curr_buf].p_index;
130: for(j=0 ;j<imax; j++,sample++)
131: msg.arg[j] = *sample;
132:
133: /* Let hardclock() know you've finished the dirty job */
134: pbuf->prof_area[curr_buf].p_full = FALSE;
135:
136: /*
137: * Store the number of samples actually sent
138: * as the last element of the array.
139: */
140: msg.arg[SIZE_PROF_BUFFER] = imax;
141:
142: mr = mach_msg(&(msg.head), MACH_SEND_MSG,
143: sizeof(struct message), 0,
144: MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
145: MACH_PORT_NULL);
146:
147: if (mr != MACH_MSG_SUCCESS) {
148: printf("profile_thread: mach_msg failed returned %x\n",(int)mr);
149: }
150:
151: if (buf_entry->wakeme)
152: thread_wakeup((event_t) &buf_entry->wakeme);
153: kmem_free(kernel_map, (buf_to_send_t) buf_entry,
154: sizeof(struct buf_to_send));
155:
156: }
157:
158: }
159: /* The profile thread has been signalled to exit. There may still
160: be sample data queued for us, which we must now throw away.
161: Once we set profile_thread_id to null, hardclock() will stop
162: queueing any additional samples, so we do not need to alter
163: the interrupt level. */
164: profile_thread_id = THREAD_NULL;
165: while (1) {
166: mpdequeue_head(&prof_queue, &prof_queue_entry);
167: if ((buf_entry = (buf_to_send_t) prof_queue_entry) == NULLBTS)
168: break;
169: if (buf_entry->wakeme)
170: thread_wakeup((event_t) &buf_entry->wakeme);
171: kmem_free(kernel_map, (buf_to_send_t) buf_entry,
172: sizeof(struct buf_to_send));
173: }
174:
175: thread_halt_self();
176: }
177:
178:
179:
180: #include <mach/message.h>
181:
182: void
183: send_last_sample_buf(th)
184: thread_t th;
185: {
186: register spl_t s;
187: buf_to_send_t buf_entry;
188: vm_offset_t vm_buf_entry;
189:
190: if (th->profil_buffer == NULLPBUF)
191: return;
192:
193: /* Ask for the sending of the last PC buffer.
194: * Make a request to the profile_thread by inserting
195: * the buffer in the send queue, and wake it up.
196: * The last buffer must be inserted at the head of the
197: * send queue, so the profile_thread handles it immediatly.
198: */
199: if (kmem_alloc( kernel_map, &vm_buf_entry,
200: sizeof(struct buf_to_send)) != KERN_SUCCESS)
201: return;
202: buf_entry = (buf_to_send_t) vm_buf_entry;
203: buf_entry->thread = (int *) th;
204: buf_entry->number = th->profil_buffer->prof_index;
205:
206: /* Watch out in case profile thread exits while we are about to
207: queue data for it. */
208: s = splsched();
209: if (profile_thread_id != THREAD_NULL) {
210: simple_lock_t lock;
211: buf_entry->wakeme = 1;
212: mpenqueue_tail( &prof_queue, &(buf_entry->list));
213: thread_wakeup((event_t) profile_thread);
214: assert_wait((event_t) &buf_entry->wakeme, TRUE);
215: splx(s);
216: thread_block((void (*)()) 0);
217: } else {
218: splx(s);
219: kmem_free(kernel_map, vm_buf_entry, sizeof(struct buf_to_send));
220: }
221: }
222:
223: /*
224: * Profile current thread
225: */
226:
227: profile(pc) {
228:
229: /* Find out which thread has been interrupted. */
230: thread_t it_thread = current_thread();
231: int inout_val = pc;
232: buf_to_send_t buf_entry;
233: vm_offset_t vm_buf_entry;
234: int *val;
235: /*
236: * Test if the current thread is to be sampled
237: */
238: if (it_thread->thread_profiled) {
239: /* Inserts the PC value in the buffer of the thread */
240: set_pbuf_value(it_thread->profil_buffer, &inout_val);
241: switch(inout_val) {
242: case 0:
243: if (profile_thread_id == THREAD_NULL) {
244: reset_pbuf_area(it_thread->profil_buffer);
245: } else printf("ERROR : hardclock : full buffer unsent\n");
246: break;
247: case 1:
248: /* Normal case, value successfully inserted */
249: break;
250: case 2 :
251: /*
252: * The value we have just inserted caused the
253: * buffer to be full, and ready to be sent.
254: * If profile_thread_id is null, the profile
255: * thread has been killed. Since this generally
256: * happens only when the O/S server task of which
257: * it is a part is killed, it is not a great loss
258: * to throw away the data.
259: */
260: if (profile_thread_id == THREAD_NULL ||
261: kmem_alloc(kernel_map,
262: &vm_buf_entry ,
263: sizeof(struct buf_to_send)) !=
264: KERN_SUCCESS) {
265: reset_pbuf_area(it_thread->profil_buffer);
266: break;
267: }
268: buf_entry = (buf_to_send_t) vm_buf_entry;
269: buf_entry->thread = (int *)it_thread;
270: buf_entry->number =
271: (it_thread->profil_buffer)->prof_index;
272: mpenqueue_tail(&prof_queue, &(buf_entry->list));
273:
274: /* Switch to another buffer */
275: reset_pbuf_area(it_thread->profil_buffer);
276:
277: /* Wake up the profile thread */
278: if (profile_thread_id != THREAD_NULL)
279: thread_wakeup((event_t) profile_thread);
280: break;
281:
282: default:
283: printf("ERROR: profile : unexpected case\n");
284: }
285: }
286: }
287:
288:
289: /* The task parameter in this and the subsequent routine is needed for
290: MiG, even though it is not used in the function itself. */
291:
292: kern_return_t
293: mach_sample_thread (task, reply, cur_thread)
294: ipc_space_t task;
295: ipc_object_t reply;
296: thread_t cur_thread;
297: {
298: /*
299: * This routine is called every time that a new thread has made
300: * a request for the sampling service. We must keep track of the
301: * correspondance between it's identity (cur_thread) and the port
302: * we are going to use as a reply port to send out the samples resulting
303: * from its execution.
304: */
305: prof_data_t pbuf;
306: vm_offset_t vmpbuf;
307:
308: if (reply != MACH_PORT_NULL) {
309: if (cur_thread->thread_profiled && cur_thread->thread_profiled_own) {
310: if (reply == cur_thread->profil_buffer->prof_port)
311: return KERN_SUCCESS;
312: mach_sample_thread(MACH_PORT_NULL, cur_thread);
313: }
314: /* Start profiling this thread , do the initialization. */
315: alloc_pbuf_area(pbuf, vmpbuf);
316: if ((cur_thread->profil_buffer = pbuf) == NULLPBUF) {
317: printf("ERROR:mach_sample_thread:cannot allocate pbuf\n");
318: return KERN_RESOURCE_SHORTAGE;
319: } else {
320: if (!set_pbuf_nb(pbuf, NB_PROF_BUFFER-1)) {
321: printf("ERROR:mach_sample_thread:cannot set pbuf_nb\n");
322: return KERN_FAILURE;
323: }
324: reset_pbuf_area(pbuf);
325: }
326:
327: pbuf->prof_port = reply;
328: cur_thread->thread_profiled = TRUE;
329: cur_thread->thread_profiled_own = TRUE;
330: if (profile_thread_id == THREAD_NULL)
331: profile_thread_id = kernel_thread(current_task(), profile_thread);
332: } else {
333: if (!cur_thread->thread_profiled_own)
334: cur_thread->thread_profiled = FALSE;
335: if (!cur_thread->thread_profiled)
336: return KERN_SUCCESS;
337:
338: send_last_sample_buf(cur_thread);
339:
340: /* Stop profiling this thread, do the cleanup. */
341:
342: cur_thread->thread_profiled_own = FALSE;
343: cur_thread->thread_profiled = FALSE;
344: dealloc_pbuf_area(cur_thread->profil_buffer);
345: cur_thread->profil_buffer = NULLPBUF;
346: }
347:
348: return KERN_SUCCESS;
349: }
350:
351: kern_return_t
352: mach_sample_task (task, reply, cur_task)
353: ipc_space_t task;
354: ipc_object_t reply;
355: task_t cur_task;
356: {
357: prof_data_t pbuf=cur_task->profil_buffer;
358: vm_offset_t vmpbuf;
359: int turnon = (reply != MACH_PORT_NULL);
360:
361: if (turnon) {
362: if (cur_task->task_profiled) {
363: if (cur_task->profil_buffer->prof_port == reply)
364: return KERN_SUCCESS;
365: (void) mach_sample_task(task, MACH_PORT_NULL, cur_task);
366: }
367: if (pbuf == NULLPBUF) {
368: alloc_pbuf_area(pbuf, vmpbuf);
369: if (pbuf == NULLPBUF) {
370: return KERN_RESOURCE_SHORTAGE;
371: }
372: cur_task->profil_buffer = pbuf;
373: }
374: if (!set_pbuf_nb(pbuf, NB_PROF_BUFFER-1)) {
375: return KERN_FAILURE;
376: }
377: reset_pbuf_area(pbuf);
378: pbuf->prof_port = reply;
379: }
380:
381: if (turnon != cur_task->task_profiled) {
382: int actual,i,sentone;
383: thread_t thread;
384:
385: if (turnon && profile_thread_id == THREAD_NULL)
386: profile_thread_id =
387: kernel_thread(current_task(), profile_thread);
388: cur_task->task_profiled = turnon;
389: actual = cur_task->thread_count;
390: sentone = 0;
391: for (i=0, thread=(thread_t) queue_first(&cur_task->thread_list);
392: i < actual;
393: i++, thread=(thread_t) queue_next(&thread->thread_list)) {
394: if (!thread->thread_profiled_own) {
395: thread->thread_profiled = turnon;
396: if (turnon)
397: thread->profil_buffer = cur_task->profil_buffer;
398: else if (!sentone) {
399: send_last_sample_buf(thread);
400: sentone = 1;
401: }
402: }
403: }
404: if (!turnon) {
405: dealloc_pbuf_area(pbuf);
406: cur_task->profil_buffer = NULLPBUF;
407: }
408: }
409:
410: return KERN_SUCCESS;
411: }
412:
413: #endif /* 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.