|
|
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.