|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_FREE_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Copyright (c) 1993 The University of Utah and ! 27: * the Computer Systems Laboratory (CSL). All rights reserved. ! 28: * ! 29: * Permission to use, copy, modify and distribute this software and its ! 30: * documentation is hereby granted, provided that both the copyright ! 31: * notice and this permission notice appear in all copies of the ! 32: * software, derivative works or modified versions, and any portions ! 33: * thereof, and that both notices appear in supporting documentation. ! 34: * ! 35: * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS ! 36: * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF ! 37: * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 38: * ! 39: * CSL requests users of this software to return to [email protected] any ! 40: * improvements that they make and grant CSL redistribution rights. ! 41: * ! 42: * Author: Bryan Ford, University of Utah CSL ! 43: * ! 44: * File: thread_act.h ! 45: * ! 46: * thread activation definitions ! 47: */ ! 48: #ifndef _KERN_THREAD_ACT_H_ ! 49: #define _KERN_THREAD_ACT_H_ ! 50: ! 51: #include <mach/mach_types.h> ! 52: #include <mach/rpc.h> ! 53: #include <mach/vm_param.h> ! 54: #include <mach/thread_info.h> ! 55: #include <mach/exception_types.h> ! 56: ! 57: ! 58: #ifdef MACH_KERNEL_PRIVATE ! 59: #include <mach_assert.h> ! 60: #include <xkmachkernel.h> ! 61: #include <thread_swapper.h> ! 62: #include <cputypes.h> ! 63: ! 64: #include <kern/lock.h> ! 65: #include <kern/queue.h> ! 66: #include <kern/etap_macros.h> ! 67: #include <kern/thread.h> ! 68: #include <kern/thread_pool.h> ! 69: #include <ipc/ipc_port.h> ! 70: #include <machine/thread_act.h> ! 71: ! 72: /* Here is a description of the states an thread_activation may be in. ! 73: * ! 74: * An activation always has a valid task pointer, and it is always constant. ! 75: * The activation is only linked onto the task's activation list until ! 76: * the activation is terminated. ! 77: * ! 78: * An activation is in use or not, depending on whether its thread ! 79: * pointer is nonzero. If it is not in use, it is just sitting idly ! 80: * waiting to be used by a thread. The thread holds a reference on ! 81: * the activation while using it. ! 82: * ! 83: * An activation lives on an thread_pool if its pool_port pointer is nonzero. ! 84: * When in use, it can still live on an thread_pool, but it is not actually ! 85: * linked onto the thread_pool's list of available activations. In this case, ! 86: * the act will return to its thread_pool as soon as it becomes unused. ! 87: * ! 88: * An activation is active until thread_terminate is called on it; ! 89: * then it is inactive, waiting for all references to be dropped. ! 90: * Future control operations on the terminated activation will fail, ! 91: * with the exception that act_yank still works if the activation is ! 92: * still on an RPC chain. A terminated activation always has null ! 93: * thread and pool_port pointers. ! 94: * ! 95: * An activation is suspended when suspend_count > 0. ! 96: * A suspended activation can live on an thread_pool, but it is not ! 97: * actually linked onto the thread_pool while suspended. ! 98: * ! 99: * Locking note: access to data relevant to scheduling state (user_stop_count, ! 100: * suspend_count, handlers, special_handler) is controlled by the combination ! 101: * of locks acquired by act_lock_thread(). That is, not only must act_lock() ! 102: * be held, but RPC through the activation must be frozen (so that the ! 103: * thread pointer doesn't change). If a shuttle is associated with the ! 104: * activation, then its thread_lock() must also be acquired to change these ! 105: * data. Regardless of whether a shuttle is present, the data must be ! 106: * altered at splsched(). ! 107: */ ! 108: ! 109: typedef struct ReturnHandler { ! 110: struct ReturnHandler *next; ! 111: void (*handler)(struct ReturnHandler *rh, ! 112: struct thread_activation *thr_act); ! 113: } ReturnHandler; ! 114: ! 115: typedef struct thread_activation { ! 116: ! 117: /*** task linkage ***/ ! 118: ! 119: /* Links for task's circular list of activations. The activation ! 120: * is only on the task's activation list while active. Must be ! 121: * first. ! 122: */ ! 123: queue_chain_t thr_acts; ! 124: ! 125: /* Indicators for whether this activation is in the midst of ! 126: * resuming or has already been resumed in a kernel-loaded ! 127: * task -- these flags are basically for quick access to ! 128: * this information. ! 129: */ ! 130: boolean_t kernel_loaded; /* running in kernel-loaded task */ ! 131: boolean_t kernel_loading; /* about to run kernel-loaded */ ! 132: ! 133: /*** Machine-dependent state ***/ ! 134: struct MachineThrAct mact; ! 135: ! 136: /*** Consistency ***/ ! 137: decl_mutex_data(,lock) ! 138: decl_simple_lock_data(,sched_lock) ! 139: int ref_count; ! 140: ! 141: /* Reference to the task this activation is in. ! 142: * Constant for the life of the activation ! 143: */ ! 144: struct task *task; ! 145: vm_map_t map; /* cached current map */ ! 146: ! 147: /*** thread_pool-related stuff ***/ ! 148: /* Port containing the thread_pool this activation normally lives ! 149: * on, zero if none. The port (really the thread_pool) holds a ! 150: * reference to the activation as long as this is nonzero (even when ! 151: * the activation isn't actually on the thread_pool's list). ! 152: */ ! 153: struct ipc_port *pool_port; ! 154: ! 155: /* Link on the thread_pool's list of activations. ! 156: * The activation is only actually on the thread_pool's list ! 157: * (and hence this is valid) when not in use (thread == 0) and ! 158: * not suspended (suspend_count == 0). ! 159: */ ! 160: struct thread_activation *thread_pool_next; ! 161: ! 162: /* User stack location and size for initialization on migrating RPCs */ ! 163: vm_offset_t user_stack; ! 164: vm_size_t user_stack_size; ! 165: ! 166: /* ! 167: * Entry point for upcall w/o registered subsystem and pointer ! 168: * to return code ! 169: */ ! 170: entry_function_t user_entry; ! 171: ! 172: /* RPC state */ ! 173: union { ! 174: struct { ! 175: rpc_subsystem_t r_subsystem; ! 176: #if 0 /* Grenoble */ ! 177: mach_rpc_id_t r_routine_num; ! 178: mach_rpc_signature_t r_sig_ptr; ! 179: mach_rpc_size_t r_sig_size; ! 180: #else ! 181: rpc_id_t r_routine_num; ! 182: rpc_signature_t r_sig_ptr; /* Stored Client Sig Ptr */ ! 183: rpc_size_t r_sig_size; /* Size of Sig stored */ ! 184: struct rpc_signature r_sigbuf; /* Static Reservation of Sig Mem */ ! 185: routine_descriptor_t r_sigbufp; /* For dynamic storage of Sig */ ! 186: vm_size_t r_sigbuf_size; /* Size of buffer allocated for sig */ ! 187: #endif ! 188: vm_offset_t r_new_argv; ! 189: vm_offset_t *r_arg_buf; ! 190: vm_offset_t r_arg_buf_data[RPC_KBUF_SIZE]; ! 191: rpc_copy_state_t r_state; ! 192: rpc_copy_state_data_t r_state_data[RPC_DESC_COUNT]; ! 193: unsigned int r_port_flags; ! 194: ipc_port_t r_local_port; ! 195: void *r_kkt_args; ! 196: } regular; ! 197: struct { ! 198: ipc_port_t r_port; ! 199: ipc_port_t r_exc_port; ! 200: int r_exc_flavor; ! 201: mach_msg_type_number_t r_ostate_cnt; ! 202: exception_data_type_t r_code[EXCEPTION_CODE_MAX]; ! 203: #if ETAP_EVENT_MONITOR ! 204: exception_type_t r_exception; ! 205: #endif ! 206: } exception; ! 207: } rpc_state; ! 208: ! 209: /*** Thread linkage ***/ ! 210: /* Shuttle using this activation, zero if not in use. The shuttle ! 211: * holds a reference on the activation while this is nonzero. ! 212: */ ! 213: struct thread_shuttle *thread; ! 214: ! 215: /* The rest in this section is only valid when thread is nonzero. */ ! 216: ! 217: /* Next higher and next lower activation on the thread's activation ! 218: * stack. For a topmost activation or the null_act, higher is ! 219: * undefined. The bottommost activation is always the null_act. ! 220: */ ! 221: struct thread_activation *higher, *lower; ! 222: ! 223: /* Alert bits pending at this activation; some of them may have ! 224: * propagated from lower activations. ! 225: */ ! 226: unsigned alerts; ! 227: ! 228: /* Mask of alert bits to be allowed to pass through from lower levels. ! 229: */ ! 230: unsigned alert_mask; ! 231: ! 232: #if 0 /* Grenoble */ ! 233: /* Saved policy and priority of shuttle if changed to migrate into ! 234: * higher-priority or more real-time task. Only valid if ! 235: * saved_sched_stamp is nonzero and equal to the sched_change_stamp ! 236: * in the thread_shuttle. (Otherwise, the policy or priority has ! 237: * been explicitly changed in the meantime, and the saved values ! 238: * are invalid.) ! 239: */ ! 240: policy_t saved_policy; ! 241: integer_t saved_base_priority; ! 242: unsigned int saved_sched_change_stamp; ! 243: #endif ! 244: /*** Control information ***/ ! 245: ! 246: /* Number of outstanding suspensions on this activation. */ ! 247: int suspend_count; ! 248: ! 249: /* User-visible scheduling state */ ! 250: int user_stop_count; /* outstanding stops */ ! 251: ! 252: /* ast is needed - see ast.h */ ! 253: int ast; ! 254: ! 255: #if THREAD_SWAPPER ! 256: /* task swapper */ ! 257: int swap_state; /* swap state (or unswappable flag)*/ ! 258: queue_chain_t swap_queue; /* links on swap queues */ ! 259: #if MACH_ASSERT ! 260: boolean_t kernel_stack_swapped_in; ! 261: /* debug for thread swapping */ ! 262: #if THREAD_SWAP_UNWIRE_USER_STACK ! 263: boolean_t user_stack_swapped_in; ! 264: /* debug for thread swapping */ ! 265: #endif /* THREAD_SWAP_UNWIRE_USER_STACK */ ! 266: #endif /* MACH_ASSERT */ ! 267: #endif /* THREAD_SWAPPER */ ! 268: ! 269: /* This is normally true, but is set to false when the ! 270: * activation is terminated. ! 271: */ ! 272: int active; ! 273: ! 274: /* Chain of return handlers to be called before the thread is ! 275: * allowed to return to this invocation ! 276: */ ! 277: ReturnHandler *handlers; ! 278: ! 279: /* A special ReturnHandler attached to the above chain to ! 280: * handle suspension and such ! 281: */ ! 282: ReturnHandler special_handler; ! 283: ! 284: /* Special ports attached to this activation */ ! 285: struct ipc_port *ith_self; /* not a right, doesn't hold ref */ ! 286: struct ipc_port *ith_sself; /* a send right */ ! 287: struct exception_action exc_actions[EXC_TYPES_COUNT]; ! 288: ! 289: /* A list of ulocks (a lock set element) currently held by the thread ! 290: */ ! 291: queue_head_t held_ulocks; ! 292: ! 293: #if XKMACHKERNEL ! 294: void *xk_resources; ! 295: #endif /* XKMACHKERNEL */ ! 296: ! 297: #if MACH_PROF ! 298: /* Profiling data structures */ ! 299: boolean_t act_profiled; /* is activation being profiled? */ ! 300: boolean_t act_profiled_own; ! 301: /* is activation being profiled ! 302: * on its own ? */ ! 303: struct prof_data *profil_buffer;/* prof struct if either is so */ ! 304: #endif /* MACH_PROF */ ! 305: #ifdef MACH_BSD ! 306: /* ! 307: * WARNING: you must change this constant if the size of ! 308: * user.h:struct uthread changes ! 309: */ ! 310: unsigned char bsd_space[288]; ! 311: #endif ! 312: ! 313: } Thread_Activation; ! 314: ! 315: /* RPC state fields */ ! 316: #define r_subsystem rpc_state.regular.r_subsystem ! 317: #define r_routine_num rpc_state.regular.r_routine_num ! 318: #define r_sig_ptr rpc_state.regular.r_sig_ptr ! 319: #define r_sig_size rpc_state.regular.r_sig_size ! 320: #define r_sigbuf rpc_state.regular.r_sigbuf ! 321: #define r_sigbufp rpc_state.regular.r_sigbufp ! 322: #define r_sigbuf_size rpc_state.regular.r_sigbuf_size ! 323: #define r_new_argv rpc_state.regular.r_new_argv ! 324: #define r_arg_buf rpc_state.regular.r_arg_buf ! 325: #define r_arg_buf_data rpc_state.regular.r_arg_buf_data ! 326: #define r_state rpc_state.regular.r_state ! 327: #define r_state_data rpc_state.regular.r_state_data ! 328: #define r_port_flags rpc_state.regular.r_port_flags ! 329: #define r_local_port rpc_state.regular.r_local_port ! 330: #define r_kkt_args rpc_state.regular.r_kkt_args ! 331: #define r_port rpc_state.exception.r_port ! 332: #define r_exc_port rpc_state.exception.r_exc_port ! 333: #define r_exc_flavor rpc_state.exception.r_exc_flavor ! 334: #define r_ostate_cnt rpc_state.exception.r_ostate_cnt ! 335: #define r_code rpc_state.exception.r_code ! 336: #define r_exception rpc_state.exception.r_exception ! 337: ! 338: /* Alert bits */ ! 339: #define SERVER_TERMINATED 0x01 ! 340: #define ORPHANED 0x02 ! 341: #define CLIENT_TERMINATED 0x04 ! 342: #define TIME_CONSTRAINT_UNSATISFIED 0x08 ! 343: ! 344: #if THREAD_SWAPPER ! 345: /* ! 346: * Encapsulate the actions needed to ensure that next lower act on ! 347: * RPC chain is swapped in. Used at base spl; assumes rpc_lock() ! 348: * of thread is held; if port is non-null, assumes its ip_lock() ! 349: * is also held. ! 350: */ ! 351: #define act_switch_swapcheck(thread, port) \ ! 352: MACRO_BEGIN \ ! 353: thread_act_t __act__ = thread->top_act; \ ! 354: \ ! 355: while (__act__->lower) { \ ! 356: thread_act_t __l__ = __act__->lower; \ ! 357: \ ! 358: if (__l__->swap_state == TH_SW_IN || \ ! 359: __l__->swap_state == TH_SW_UNSWAPPABLE) \ ! 360: break; \ ! 361: /* \ ! 362: * XXX - Do we need to reference __l__? \ ! 363: */ \ ! 364: if (port) \ ! 365: ip_unlock(port); \ ! 366: if (!thread_swapin_blocking(__l__)) \ ! 367: panic("act_switch_swapcheck: !active"); \ ! 368: if (port) \ ! 369: ip_lock(port); \ ! 370: if (__act__->lower == __l__) \ ! 371: break; \ ! 372: } \ ! 373: MACRO_END ! 374: ! 375: #else /* !THREAD_SWAPPER */ ! 376: ! 377: #define act_switch_swapcheck(thread, port) ! 378: ! 379: #endif /* !THREAD_SWAPPER */ ! 380: ! 381: #define act_lock_init(thr_act) mutex_init(&(thr_act)->lock, ETAP_THREAD_ACT) ! 382: #define act_lock(thr_act) mutex_lock(&(thr_act)->lock) ! 383: #define act_lock_try(thr_act) mutex_try(&(thr_act)->lock) ! 384: #define act_unlock(thr_act) mutex_unlock(&(thr_act)->lock) ! 385: ! 386: /* Sanity check the ref count. If it is 0, we may be doubly zfreeing. ! 387: * If it is larger than max int, it has been corrupted, probably by being ! 388: * modified into an address (this is architecture dependent, but it's ! 389: * safe to assume there cannot really be max int references). ! 390: */ ! 391: #define ACT_MAX_REFERENCES \ ! 392: (unsigned)(~0 ^ (1 << (sizeof(int)*BYTE_SIZE - 1))) ! 393: ! 394: #define act_reference(thr_act) \ ! 395: MACRO_BEGIN \ ! 396: if (thr_act) { \ ! 397: act_lock(thr_act); \ ! 398: assert((thr_act)->ref_count < ACT_MAX_REFERENCES); \ ! 399: if ((thr_act)->ref_count <= 0) \ ! 400: panic("act_reference: already freed"); \ ! 401: (thr_act)->ref_count++; \ ! 402: act_unlock(thr_act); \ ! 403: } \ ! 404: MACRO_END ! 405: ! 406: #define act_locked_act_reference(thr_act) \ ! 407: MACRO_BEGIN \ ! 408: if (thr_act) { \ ! 409: assert((thr_act)->ref_count < ACT_MAX_REFERENCES); \ ! 410: if ((thr_act)->ref_count <= 0) \ ! 411: panic("a_l_act_reference: already freed"); \ ! 412: (thr_act)->ref_count++; \ ! 413: } \ ! 414: MACRO_END ! 415: ! 416: #define sigbuf_dealloc(thr_act) \ ! 417: if ((thr_act->r_sigbufp) && (thr_act->r_sigbuf_size > \ ! 418: sizeof(thr_act->r_sigbuf))) \ ! 419: { \ ! 420: KFREE((vm_offset_t)thr_act->r_sigbufp, \ ! 421: thr_act->r_sigbuf_size, \ ! 422: thr_act->r_port_flags & IPC_PORT_FLAGS_RT); \ ! 423: thr_act->r_sigbuf_size = 0; \ ! 424: } ! 425: ! 426: #define act_deallocate(thr_act) \ ! 427: MACRO_BEGIN \ ! 428: if (thr_act) { \ ! 429: int new_value; \ ! 430: act_lock(thr_act); \ ! 431: assert((thr_act)->ref_count > 0 && \ ! 432: (thr_act)->ref_count <= ACT_MAX_REFERENCES); \ ! 433: new_value = --(thr_act)->ref_count; \ ! 434: if (new_value == 0) { \ ! 435: sigbuf_dealloc(thr_act); \ ! 436: act_free(thr_act); \ ! 437: } \ ! 438: else act_unlock(thr_act); \ ! 439: } \ ! 440: MACRO_END ! 441: ! 442: #define act_locked_act_deallocate(thr_act) \ ! 443: MACRO_BEGIN \ ! 444: if (thr_act) { \ ! 445: int new_value; \ ! 446: assert((thr_act)->ref_count > 0 && \ ! 447: (thr_act)->ref_count <= ACT_MAX_REFERENCES); \ ! 448: new_value = --(thr_act)->ref_count; \ ! 449: if (new_value == 0) { \ ! 450: panic("a_l_act_deallocate: would free act"); \ ! 451: } \ ! 452: } \ ! 453: MACRO_END ! 454: ! 455: ! 456: extern void act_init(void); ! 457: extern kern_return_t act_disable_task_locked(thread_act_t); ! 458: extern void thread_release(thread_act_t); ! 459: extern kern_return_t thread_dowait(thread_act_t, boolean_t); ! 460: extern void thread_hold(thread_act_t); ! 461: extern void nudge(thread_act_t); ! 462: ! 463: extern kern_return_t act_set_thread_pool(thread_act_t, ipc_port_t); ! 464: extern kern_return_t act_locked_act_set_thread_pool(thread_act_t, ipc_port_t); ! 465: extern kern_return_t thread_get_special_port(thread_act_t, int, ! 466: ipc_port_t *); ! 467: extern kern_return_t thread_set_special_port(thread_act_t, int, ! 468: ipc_port_t); ! 469: extern thread_t act_lock_thread(thread_act_t); ! 470: extern void act_unlock_thread(thread_act_t); ! 471: extern void install_special_handler(thread_act_t); ! 472: extern thread_act_t thread_lock_act(thread_t); ! 473: extern void thread_unlock_act(thread_t); ! 474: extern void act_attach(thread_act_t, thread_t, unsigned); ! 475: extern void act_execute_returnhandlers(void); ! 476: extern void act_detach(thread_act_t); ! 477: extern void act_free(thread_act_t); ! 478: ! 479: /* machine-dependent functions */ ! 480: extern void act_machine_return(kern_return_t); ! 481: extern void act_machine_init(void); ! 482: extern kern_return_t act_machine_create(struct task *, thread_act_t); ! 483: extern void act_machine_destroy(thread_act_t); ! 484: extern kern_return_t act_machine_set_state(thread_act_t, ! 485: thread_flavor_t, thread_state_t, ! 486: mach_msg_type_number_t ); ! 487: extern kern_return_t act_machine_get_state(thread_act_t, ! 488: thread_flavor_t, thread_state_t, ! 489: mach_msg_type_number_t *); ! 490: extern void act_machine_switch_pcb(thread_act_t); ! 491: ! 492: extern kern_return_t act_create(task_t, thread_act_params_t params, ! 493: thread_act_t *); ! 494: extern kern_return_t act_get_state(thread_act_t, int, thread_state_t, ! 495: mach_msg_type_number_t *); ! 496: extern kern_return_t act_set_state(thread_act_t, int, thread_state_t, ! 497: mach_msg_type_number_t); ! 498: ! 499: extern int dump_act(thread_act_t); /* debugging */ ! 500: ! 501: #define current_act_fast() (current_thread()->top_act) ! 502: #define current_act_slow() ((current_thread()) ? \ ! 503: current_act_fast() : \ ! 504: THR_ACT_NULL) ! 505: ! 506: #define current_act() current_act_slow() /* JMM - til we find the culprit */ ! 507: ! 508: #else /* !MACH_KERNEL_PRIVATE */ ! 509: ! 510: extern thread_act_t current_act(void); ! 511: ! 512: #endif /* !MACH_KERNEL_PRIVATE */ ! 513: ! 514: /* Exported to world */ ! 515: extern kern_return_t act_alert(thread_act_t, unsigned); ! 516: extern kern_return_t act_alert_mask(thread_act_t, unsigned ); ! 517: extern kern_return_t post_alert(thread_act_t, unsigned); ! 518: ! 519: extern kern_return_t thread_abort(thread_act_t); ! 520: extern kern_return_t thread_abort_safely(thread_act_t); ! 521: extern kern_return_t thread_resume(thread_act_t); ! 522: extern kern_return_t thread_suspend(thread_act_t); ! 523: extern kern_return_t thread_terminate(thread_act_t); ! 524: ! 525: typedef void (thread_apc_handler_t)(thread_act_t); ! 526: ! 527: extern kern_return_t thread_apc_set(thread_act_t, thread_apc_handler_t); ! 528: extern kern_return_t thread_apc_clear(thread_act_t, thread_apc_handler_t); ! 529: ! 530: extern void set_act_map(thread_act_t, vm_map_t); ! 531: ! 532: extern void *get_bsdthread_info(thread_act_t); ! 533: extern void set_bsdthread_info(thread_act_t, void *); ! 534: extern task_t get_threadtask(thread_act_t); ! 535: ! 536: #endif /* _KERN_THREAD_ACT_H_ */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.