--- Gnu-Mach/kern/task.c 2020/09/02 04:36:57 1.1.1.1 +++ Gnu-Mach/kern/task.c 2020/09/02 04:54:07 1.1.1.7 @@ -1,25 +1,25 @@ -/* +/* * Mach Operating System * Copyright (c) 1993-1988 Carnegie Mellon University * All Rights Reserved. - * + * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. - * + * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * + * * Carnegie Mellon requests users of this software to return to - * + * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 - * + * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ @@ -31,53 +31,42 @@ * Task management primitives implementation. */ -#include -#include -#include -#include -#include +#include #include #include #include #include +#include #include #include -#include +#include #include #include -#include +#include #include #include +#include #include /* for thread_wakeup */ #include +#include +#include #include /* for kernel_map, ipc_kernel_map */ #include /* for splsched */ -#if NET_ATM -#include -#endif - -#if NORMA_TASK -#define task_create task_create_local -#endif /* NORMA_TASK */ - task_t kernel_task = TASK_NULL; -zone_t task_zone; +struct kmem_cache task_cache; -extern void eml_init(void); -extern void eml_task_reference(task_t, task_t); -extern void eml_task_deallocate(task_t); +/* Where to send notifications about newly created tasks. */ +ipc_port_t new_task_notification = NULL; void task_init(void) { - task_zone = zinit( - sizeof(struct task), - TASK_MAX * sizeof(struct task), - TASK_CHUNK * sizeof(struct task), - 0, "tasks"); + kmem_cache_init(&task_cache, "task", sizeof(struct task), 0, + NULL, 0); eml_init(); + machine_task_module_init (); /* * Create the kernel task as the first task. @@ -85,38 +74,8 @@ void task_init(void) * for other initialization. (:-() */ (void) task_create(TASK_NULL, FALSE, &kernel_task); -} - -/* - * Create a task running in the kernel address space. It may - * have its own map of size mem_size (if 0, it uses the kernel map), - * and may have ipc privileges. - */ -task_t kernel_task_create( - task_t parent_task, - vm_size_t map_size) -{ - task_t new_task; - vm_offset_t min, max; - - /* - * Create the task. - */ - (void) task_create(parent_task, FALSE, &new_task); - - /* - * Task_create creates the task with a user-space map. - * Remove the map and replace it with the kernel map - * or a submap of the kernel map. - */ - vm_map_deallocate(new_task->map); - if (map_size == 0) - new_task->map = kernel_map; - else - new_task->map = kmem_suballoc(kernel_map, &min, &max, - map_size, FALSE); - - return new_task; + (void) task_set_name(kernel_task, "gnumach"); + vm_map_set_name(kernel_map, kernel_task->name); } kern_return_t task_create( @@ -124,27 +83,41 @@ kern_return_t task_create( boolean_t inherit_memory, task_t *child_task) /* OUT */ { - register task_t new_task; - register processor_set_t pset; + task_t new_task; + processor_set_t pset; +#if FAST_TAS int i; +#endif - new_task = (task_t) zalloc(task_zone); - if (new_task == TASK_NULL) { - panic("task_create: no memory for task structure"); - } + new_task = (task_t) kmem_cache_alloc(&task_cache); + if (new_task == TASK_NULL) + return KERN_RESOURCE_SHORTAGE; /* one ref for just being alive; one for our caller */ new_task->ref_count = 2; if (child_task == &kernel_task) { - new_task->map = kernel_map; + new_task->map = kernel_map; } else if (inherit_memory) { new_task->map = vm_map_fork(parent_task->map); } else { - new_task->map = vm_map_create(pmap_create(0), + pmap_t new_pmap = pmap_create((vm_size_t) 0); + if (new_pmap == PMAP_NULL) + new_task->map = VM_MAP_NULL; + else { + new_task->map = vm_map_create(new_pmap, round_page(VM_MIN_ADDRESS), - trunc_page(VM_MAX_ADDRESS), TRUE); + trunc_page(VM_MAX_ADDRESS)); + if (new_task->map == VM_MAP_NULL) + pmap_destroy(new_pmap); + } } + if (new_task->map == VM_MAP_NULL) { + kmem_cache_free(&task_cache, (vm_address_t) new_task); + return KERN_RESOURCE_SHORTAGE; + } + if (child_task != &kernel_task) + vm_map_set_name(new_task->map, new_task->name); simple_lock_init(&new_task->lock); queue_init(&new_task->thread_list); @@ -152,20 +125,26 @@ kern_return_t task_create( new_task->active = TRUE; new_task->user_stop_count = 0; new_task->thread_count = 0; + new_task->faults = 0; + new_task->zero_fills = 0; + new_task->reactivations = 0; + new_task->pageins = 0; + new_task->cow_faults = 0; + new_task->messages_sent = 0; + new_task->messages_received = 0; eml_task_reference(new_task, parent_task); ipc_task_init(new_task, parent_task); - -#if NET_ATM - new_task->nw_ep_owned = 0; -#endif + machine_task_init (new_task); new_task->total_user_time.seconds = 0; new_task->total_user_time.microseconds = 0; new_task->total_system_time.seconds = 0; new_task->total_system_time.microseconds = 0; + record_time_stamp (&new_task->creation_time); + if (parent_task != TASK_NULL) { task_lock(parent_task); pset = parent_task->processor_set; @@ -204,12 +183,23 @@ kern_return_t task_create( } } #endif /* FAST_TAS */ - - ipc_task_enable(new_task); -#if NORMA_TASK - new_task->child_node = -1; -#endif /* NORMA_TASK */ + if (parent_task == TASK_NULL) + snprintf (new_task->name, sizeof new_task->name, "%p", + new_task); + else + snprintf (new_task->name, sizeof new_task->name, "(%.*s)", + sizeof new_task->name - 3, parent_task->name); + + if (new_task_notification != NULL) { + task_reference (new_task); + task_reference (parent_task); + mach_notify_new_task (new_task_notification, + convert_task_to_port (new_task), + convert_task_to_port (parent_task)); + } + + ipc_task_enable(new_task); *child_task = new_task; return KERN_SUCCESS; @@ -223,10 +213,10 @@ kern_return_t task_create( * is never in this task. */ void task_deallocate( - register task_t task) + task_t task) { - register int c; - register processor_set_t pset; + int c; + processor_set_t pset; if (task == TASK_NULL) return; @@ -237,13 +227,7 @@ void task_deallocate( if (c != 0) return; -#if NORMA_TASK - if (task->map == VM_MAP_NULL) { - /* norma placeholder task */ - zfree(task_zone, (vm_offset_t) task); - return; - } -#endif /* NORMA_TASK */ + machine_task_terminate (task); eml_task_deallocate(task); @@ -254,11 +238,11 @@ void task_deallocate( pset_deallocate(pset); vm_map_deallocate(task->map); is_release(task->itk_space); - zfree(task_zone, (vm_offset_t) task); + kmem_cache_free(&task_cache, (vm_offset_t) task); } void task_reference( - register task_t task) + task_t task) { if (task == TASK_NULL) return; @@ -275,11 +259,11 @@ void task_reference( * (kern/thread.c) about problems with terminating the "current task." */ kern_return_t task_terminate( - register task_t task) + task_t task) { - register thread_t thread, cur_thread; - register queue_head_t *list; - register task_t cur_task; + thread_t thread, cur_thread; + queue_head_t *list; + task_t cur_task; spl_t s; if (task == TASK_NULL) @@ -289,13 +273,6 @@ kern_return_t task_terminate( cur_task = current_task(); cur_thread = current_thread(); -#if NET_ATM - /* - * Shut down networking. - */ - mk_endpoint_collect(task); -#endif - /* * Deactivate task so that it can't be terminated again, * and so lengthy operations in progress will abort. @@ -325,6 +302,7 @@ kern_return_t task_terminate( thread_terminate(cur_thread); return KERN_FAILURE; } + task_hold_locked(task); task->active = FALSE; queue_remove(list, cur_thread, thread_t, thread_list); thread_unlock(cur_thread); @@ -378,6 +356,7 @@ kern_return_t task_terminate( task_unlock(task); return KERN_FAILURE; } + task_hold_locked(task); task->active = FALSE; task_unlock(task); } @@ -388,9 +367,8 @@ kern_return_t task_terminate( * If this is the current task, the current thread will * be left running. */ - ipc_task_disable(task); - (void) task_hold(task); (void) task_dowait(task,TRUE); /* may block */ + ipc_task_disable(task); /* * Terminate each thread in the task. @@ -413,7 +391,7 @@ kern_return_t task_terminate( task_unlock(task); thread_force_terminate(thread); thread_deallocate(thread); - thread_block((void (*)()) 0); + thread_block(thread_no_continuation); task_lock(task); } task_unlock(task); @@ -455,20 +433,18 @@ kern_return_t task_terminate( * Suspend execution of the specified task. * This is a recursive-style suspension of the task, a count of * suspends is maintained. + * + * CONDITIONS: the task is locked and active. */ -kern_return_t task_hold( - register task_t task) +void task_hold_locked( + task_t task) { - register queue_head_t *list; - register thread_t thread, cur_thread; + queue_head_t *list; + thread_t thread, cur_thread; - cur_thread = current_thread(); + assert(task->active); - task_lock(task); - if (!task->active) { - task_unlock(task); - return KERN_FAILURE; - } + cur_thread = current_thread(); task->suspend_count++; @@ -482,6 +458,26 @@ kern_return_t task_hold( if (thread != cur_thread) thread_hold(thread); } +} + +/* + * task_hold: + * + * Suspend execution of the specified task. + * This is a recursive-style suspension of the task, a count of + * suspends is maintained. + */ +kern_return_t task_hold( + task_t task) +{ + task_lock(task); + if (!task->active) { + task_unlock(task); + return KERN_FAILURE; + } + + task_hold_locked(task); + task_unlock(task); return KERN_SUCCESS; } @@ -496,12 +492,12 @@ kern_return_t task_hold( * must_wait is true. */ kern_return_t task_dowait( - register task_t task, + task_t task, boolean_t must_wait) { - register queue_head_t *list; - register thread_t thread, cur_thread, prev_thread; - register kern_return_t ret = KERN_SUCCESS; + queue_head_t *list; + thread_t thread, cur_thread, prev_thread; + kern_return_t ret = KERN_SUCCESS; /* * Iterate through all the threads. @@ -548,10 +544,10 @@ kern_return_t task_dowait( } kern_return_t task_release( - register task_t task) + task_t task) { - register queue_head_t *list; - register thread_t thread, next; + queue_head_t *list; + thread_t thread, next; task_lock(task); if (!task->active) { @@ -583,7 +579,7 @@ kern_return_t task_threads( unsigned int actual; /* this many threads */ thread_t thread; thread_t *threads; - int i; + unsigned i; vm_size_t size, size_needed; vm_offset_t addr; @@ -660,7 +656,7 @@ kern_return_t task_threads( return KERN_RESOURCE_SHORTAGE; } - bcopy((char *) addr, (char *) newaddr, size_needed); + memcpy((void *) newaddr, (void *) addr, size_needed); kfree(addr, size); threads = (thread_t *) newaddr; } @@ -679,9 +675,9 @@ kern_return_t task_threads( } kern_return_t task_suspend( - register task_t task) + task_t task) { - register boolean_t hold; + boolean_t hold; if (task == TASK_NULL) return KERN_INVALID_ARGUMENT; @@ -730,9 +726,9 @@ kern_return_t task_suspend( } kern_return_t task_resume( - register task_t task) + task_t task) { - register boolean_t release; + boolean_t release; if (task == TASK_NULL) return KERN_INVALID_ARGUMENT; @@ -772,9 +768,13 @@ kern_return_t task_info( switch (flavor) { case TASK_BASIC_INFO: { - register task_basic_info_t basic_info; + task_basic_info_t basic_info; + + /* Allow *task_info_count to be two words smaller than + the usual amount, because creation_time is a new member + that some callers might not know about. */ - if (*task_info_count < TASK_BASIC_INFO_COUNT) { + if (*task_info_count < TASK_BASIC_INFO_COUNT - 2) { return KERN_INVALID_ARGUMENT; } @@ -795,18 +795,45 @@ kern_return_t task_info( = task->total_user_time.microseconds; basic_info->system_time.seconds = task->total_system_time.seconds; - basic_info->system_time.microseconds + basic_info->system_time.microseconds = task->total_system_time.microseconds; + read_time_stamp(&task->creation_time, + &basic_info->creation_time); task_unlock(task); - *task_info_count = TASK_BASIC_INFO_COUNT; + if (*task_info_count > TASK_BASIC_INFO_COUNT) + *task_info_count = TASK_BASIC_INFO_COUNT; + break; + } + + case TASK_EVENTS_INFO: + { + task_events_info_t event_info; + + if (*task_info_count < TASK_EVENTS_INFO_COUNT) { + return KERN_INVALID_ARGUMENT; + } + + event_info = (task_events_info_t) task_info_out; + + task_lock(task); + event_info->faults = task->faults; + event_info->zero_fills = task->zero_fills; + event_info->reactivations = task->reactivations; + event_info->pageins = task->pageins; + event_info->cow_faults = task->cow_faults; + event_info->messages_sent = task->messages_sent; + event_info->messages_received = task->messages_received; + task_unlock(task); + + *task_info_count = TASK_EVENTS_INFO_COUNT; break; } case TASK_THREAD_TIMES_INFO: { - register task_thread_times_info_t times_info; - register thread_t thread; + task_thread_times_info_t times_info; + thread_t thread; if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) { return KERN_INVALID_ARGUMENT; @@ -862,9 +889,9 @@ task_assign( boolean_t assign_threads) { kern_return_t ret = KERN_SUCCESS; - register thread_t thread, prev_thread; - register queue_head_t *list; - register processor_set_t pset; + thread_t thread, prev_thread; + queue_head_t *list; + processor_set_t pset; if (task == TASK_NULL || new_pset == PROCESSOR_SET_NULL) { return KERN_INVALID_ARGUMENT; @@ -880,7 +907,7 @@ task_assign( task->assign_active = TRUE; assert_wait((event_t)&task->assign_active, TRUE); task_unlock(task); - thread_block((void (*)()) 0); + thread_block(thread_no_continuation); task_lock(task); } @@ -1027,7 +1054,7 @@ task_assign( return KERN_FAILURE; } #endif /* MACH_HOST */ - + /* * task_assign_default: @@ -1051,6 +1078,9 @@ kern_return_t task_get_assignment( task_t task, processor_set_t *pset) { + if (task == TASK_NULL) + return KERN_INVALID_ARGUMENT; + if (!task->active) return KERN_FAILURE; @@ -1080,8 +1110,8 @@ task_priority( task->priority = priority; if (change_threads) { - register thread_t thread; - register queue_head_t *list; + thread_t thread; + queue_head_t *list; list = &task->thread_list; queue_iterate(list, thread, thread_t, thread_list) { @@ -1096,6 +1126,22 @@ task_priority( } /* + * task_set_name + * + * Set the name of task TASK to NAME. This is a debugging aid. + * NAME will be used in error messages printed by the kernel. + */ +kern_return_t +task_set_name( + task_t task, + kernel_debug_name_t name) +{ + strncpy(task->name, name, sizeof task->name - 1); + task->name[sizeof task->name - 1] = '\0'; + return KERN_SUCCESS; +} + +/* * task_collect_scan: * * Attempt to free resources owned by tasks. @@ -1103,7 +1149,7 @@ task_priority( void task_collect_scan(void) { - register task_t task, prev_task; + task_t task, prev_task; processor_set_t pset, prev_pset; prev_task = TASK_NULL; @@ -1118,6 +1164,7 @@ void task_collect_scan(void) pset_unlock(pset); simple_unlock(&all_psets_lock); + machine_task_collect (task); pmap_collect(task->map->pmap); if (prev_task != TASK_NULL) @@ -1176,7 +1223,7 @@ task_ras_control( int flavor) { kern_return_t ret = KERN_FAILURE; - + #if FAST_TAS int i; @@ -1206,7 +1253,7 @@ task_ras_control( ret = KERN_INVALID_ADDRESS; } break; - case TASK_RAS_CONTROL_PURGE_ALL_AND_INSTALL_ONE: + case TASK_RAS_CONTROL_PURGE_ALL_AND_INSTALL_ONE: /* remove all RAS an install this RAS */ for (i = 0; i < TASK_FAST_TAS_NRAS; i++) { task->fast_tas_base[i] = task->fast_tas_end[i] = 0; @@ -1227,12 +1274,33 @@ task_ras_control( } if (i == TASK_FAST_TAS_NRAS) { ret = KERN_RESOURCE_SHORTAGE; - } + } break; default: ret = KERN_INVALID_VALUE; break; } task_unlock(task); -#endif +#endif /* FAST_TAS */ return ret; } + +/* + * register_new_task_notification + * + * Register a port to which a notification about newly created + * tasks are sent. + */ +kern_return_t +register_new_task_notification( + const host_t host, + ipc_port_t notification) +{ + if (host == HOST_NULL) + return KERN_INVALID_HOST; + + if (new_task_notification != NULL) + return KERN_NO_ACCESS; + + new_task_notification = notification; + return KERN_SUCCESS; +}