Annotation of OSKit-Mach/kern/profile.c, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.