17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50209230bSgjelinek * Common Development and Distribution License (the "License"). 60209230bSgjelinek * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22ff19e029SMenno Lageman * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 26ff19e029SMenno Lageman #include <sys/callb.h> 277c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 287c478bd9Sstevel@tonic-gate #include <sys/exacct.h> 297c478bd9Sstevel@tonic-gate #include <sys/id_space.h> 307c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 31ff19e029SMenno Lageman #include <sys/kstat.h> 327c478bd9Sstevel@tonic-gate #include <sys/modhash.h> 337c478bd9Sstevel@tonic-gate #include <sys/mutex.h> 347c478bd9Sstevel@tonic-gate #include <sys/proc.h> 357c478bd9Sstevel@tonic-gate #include <sys/project.h> 367c478bd9Sstevel@tonic-gate #include <sys/rctl.h> 377c478bd9Sstevel@tonic-gate #include <sys/systm.h> 387c478bd9Sstevel@tonic-gate #include <sys/task.h> 397c478bd9Sstevel@tonic-gate #include <sys/time.h> 407c478bd9Sstevel@tonic-gate #include <sys/types.h> 417c478bd9Sstevel@tonic-gate #include <sys/zone.h> 427c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 437c478bd9Sstevel@tonic-gate #include <sys/fss.h> 447c478bd9Sstevel@tonic-gate #include <sys/class.h> 457c478bd9Sstevel@tonic-gate #include <sys/project.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate /* 487c478bd9Sstevel@tonic-gate * Tasks 497c478bd9Sstevel@tonic-gate * 507c478bd9Sstevel@tonic-gate * A task is a collection of processes, associated with a common project ID 517c478bd9Sstevel@tonic-gate * and related by a common initial parent. The task primarily represents a 527c478bd9Sstevel@tonic-gate * natural process sequence with known resource usage, although it can also be 537c478bd9Sstevel@tonic-gate * viewed as a convenient grouping of processes for signal delivery, processor 547c478bd9Sstevel@tonic-gate * binding, and administrative operations. 557c478bd9Sstevel@tonic-gate * 567c478bd9Sstevel@tonic-gate * Membership and observership 577c478bd9Sstevel@tonic-gate * We can conceive of situations where processes outside of the task may wish 587c478bd9Sstevel@tonic-gate * to examine the resource usage of the task. Similarly, a number of the 597c478bd9Sstevel@tonic-gate * administrative operations on a task can be performed by processes who are 607c478bd9Sstevel@tonic-gate * not members of the task. Accordingly, we must design a locking strategy 617c478bd9Sstevel@tonic-gate * where observers of the task, who wish to examine or operate on the task, 627c478bd9Sstevel@tonic-gate * and members of task, who can perform the mentioned operations, as well as 637c478bd9Sstevel@tonic-gate * leave the task, see a consistent and correct representation of the task at 647c478bd9Sstevel@tonic-gate * all times. 657c478bd9Sstevel@tonic-gate * 667c478bd9Sstevel@tonic-gate * Locking 677c478bd9Sstevel@tonic-gate * Because the task membership is a new relation between processes, its 687c478bd9Sstevel@tonic-gate * locking becomes an additional responsibility of the pidlock/p_lock locking 697c478bd9Sstevel@tonic-gate * sequence; however, tasks closely resemble sessions and the session locking 707c478bd9Sstevel@tonic-gate * model is mostly appropriate for the interaction of tasks, processes, and 717c478bd9Sstevel@tonic-gate * procfs. 727c478bd9Sstevel@tonic-gate * 737c478bd9Sstevel@tonic-gate * kmutex_t task_hash_lock 747c478bd9Sstevel@tonic-gate * task_hash_lock is a global lock protecting the contents of the task 757c478bd9Sstevel@tonic-gate * ID-to-task pointer hash. Holders of task_hash_lock must not attempt to 767c478bd9Sstevel@tonic-gate * acquire pidlock or p_lock. 777c478bd9Sstevel@tonic-gate * uint_t tk_hold_count 787c478bd9Sstevel@tonic-gate * tk_hold_count, the number of members and observers of the current task, 797c478bd9Sstevel@tonic-gate * must be manipulated atomically. 807c478bd9Sstevel@tonic-gate * proc_t *tk_memb_list 817c478bd9Sstevel@tonic-gate * proc_t *p_tasknext 827c478bd9Sstevel@tonic-gate * proc_t *p_taskprev 837c478bd9Sstevel@tonic-gate * The task's membership list is protected by pidlock, and is therefore 847c478bd9Sstevel@tonic-gate * always acquired before any of its members' p_lock mutexes. The p_task 857c478bd9Sstevel@tonic-gate * member of the proc structure is protected by pidlock or p_lock for 867c478bd9Sstevel@tonic-gate * reading, and by both pidlock and p_lock for modification, as is done for 877c478bd9Sstevel@tonic-gate * p_sessp. The key point is that only the process can modify its p_task, 887c478bd9Sstevel@tonic-gate * and not any entity on the system. (/proc will use prlock() to prevent 897c478bd9Sstevel@tonic-gate * the process from leaving, as opposed to pidlock.) 907c478bd9Sstevel@tonic-gate * kmutex_t tk_usage_lock 917c478bd9Sstevel@tonic-gate * tk_usage_lock is a per-task lock protecting the contents of the task 927c478bd9Sstevel@tonic-gate * usage structure and tk_nlwps counter for the task.max-lwps resource 937c478bd9Sstevel@tonic-gate * control. 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate int task_hash_size = 256; 977c478bd9Sstevel@tonic-gate static kmutex_t task_hash_lock; 987c478bd9Sstevel@tonic-gate static mod_hash_t *task_hash; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate static id_space_t *taskid_space; /* global taskid space */ 1017c478bd9Sstevel@tonic-gate static kmem_cache_t *task_cache; /* kmem cache for task structures */ 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate rctl_hndl_t rc_task_lwps; 104ff19e029SMenno Lageman rctl_hndl_t rc_task_nprocs; 1057c478bd9Sstevel@tonic-gate rctl_hndl_t rc_task_cpu_time; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 108ff19e029SMenno Lageman * Resource usage is committed using task queues; if taskq_dispatch() fails 109ff19e029SMenno Lageman * due to resource constraints, the task is placed on a list for background 110ff19e029SMenno Lageman * processing by the task_commit_thread() backup thread. 111ff19e029SMenno Lageman */ 112ff19e029SMenno Lageman static kmutex_t task_commit_lock; /* protects list pointers and cv */ 113ff19e029SMenno Lageman static kcondvar_t task_commit_cv; /* wakeup task_commit_thread */ 114ff19e029SMenno Lageman static task_t *task_commit_head = NULL; 115ff19e029SMenno Lageman static task_t *task_commit_tail = NULL; 116ff19e029SMenno Lageman kthread_t *task_commit_thread; 117ff19e029SMenno Lageman 118ff19e029SMenno Lageman static void task_commit(); 119ff19e029SMenno Lageman static kstat_t *task_kstat_create(task_t *, zone_t *); 120ff19e029SMenno Lageman static void task_kstat_delete(task_t *); 121ff19e029SMenno Lageman 122ff19e029SMenno Lageman /* 1237c478bd9Sstevel@tonic-gate * static rctl_qty_t task_usage_lwps(void *taskp) 1247c478bd9Sstevel@tonic-gate * 1257c478bd9Sstevel@tonic-gate * Overview 1267c478bd9Sstevel@tonic-gate * task_usage_lwps() is the usage operation for the resource control 1277c478bd9Sstevel@tonic-gate * associated with the number of LWPs in a task. 1287c478bd9Sstevel@tonic-gate * 1297c478bd9Sstevel@tonic-gate * Return values 1307c478bd9Sstevel@tonic-gate * The number of LWPs in the given task is returned. 1317c478bd9Sstevel@tonic-gate * 1327c478bd9Sstevel@tonic-gate * Caller's context 1337c478bd9Sstevel@tonic-gate * The p->p_lock must be held across the call. 1347c478bd9Sstevel@tonic-gate */ 1357c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1367c478bd9Sstevel@tonic-gate static rctl_qty_t 1377c478bd9Sstevel@tonic-gate task_lwps_usage(rctl_t *r, proc_t *p) 1387c478bd9Sstevel@tonic-gate { 1397c478bd9Sstevel@tonic-gate task_t *t; 1407c478bd9Sstevel@tonic-gate rctl_qty_t nlwps; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate t = p->p_task; 1457c478bd9Sstevel@tonic-gate mutex_enter(&p->p_zone->zone_nlwps_lock); 1467c478bd9Sstevel@tonic-gate nlwps = t->tk_nlwps; 1477c478bd9Sstevel@tonic-gate mutex_exit(&p->p_zone->zone_nlwps_lock); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate return (nlwps); 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* 1537c478bd9Sstevel@tonic-gate * static int task_test_lwps(void *taskp, rctl_val_t *, int64_t incr, 1547c478bd9Sstevel@tonic-gate * int flags) 1557c478bd9Sstevel@tonic-gate * 1567c478bd9Sstevel@tonic-gate * Overview 1577c478bd9Sstevel@tonic-gate * task_test_lwps() is the test-if-valid-increment for the resource control 1587c478bd9Sstevel@tonic-gate * for the number of processes in a task. 1597c478bd9Sstevel@tonic-gate * 1607c478bd9Sstevel@tonic-gate * Return values 1617c478bd9Sstevel@tonic-gate * 0 if the threshold limit was not passed, 1 if the limit was passed. 1627c478bd9Sstevel@tonic-gate * 1637c478bd9Sstevel@tonic-gate * Caller's context 1647c478bd9Sstevel@tonic-gate * p->p_lock must be held across the call. 1657c478bd9Sstevel@tonic-gate */ 1667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1677c478bd9Sstevel@tonic-gate static int 1687c478bd9Sstevel@tonic-gate task_lwps_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, rctl_val_t *rcntl, 1697c478bd9Sstevel@tonic-gate rctl_qty_t incr, 1707c478bd9Sstevel@tonic-gate uint_t flags) 1717c478bd9Sstevel@tonic-gate { 1727c478bd9Sstevel@tonic-gate rctl_qty_t nlwps; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 1757c478bd9Sstevel@tonic-gate ASSERT(e->rcep_t == RCENTITY_TASK); 1767c478bd9Sstevel@tonic-gate if (e->rcep_p.task == NULL) 1777c478bd9Sstevel@tonic-gate return (0); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&(e->rcep_p.task->tk_zone->zone_nlwps_lock))); 1807c478bd9Sstevel@tonic-gate nlwps = e->rcep_p.task->tk_nlwps; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate if (nlwps + incr > rcntl->rcv_value) 1837c478bd9Sstevel@tonic-gate return (1); 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate return (0); 1867c478bd9Sstevel@tonic-gate } 187ff19e029SMenno Lageman 1887c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1897c478bd9Sstevel@tonic-gate static int 1907c478bd9Sstevel@tonic-gate task_lwps_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e, rctl_qty_t nv) { 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 1937c478bd9Sstevel@tonic-gate ASSERT(e->rcep_t == RCENTITY_TASK); 1947c478bd9Sstevel@tonic-gate if (e->rcep_p.task == NULL) 1957c478bd9Sstevel@tonic-gate return (0); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate e->rcep_p.task->tk_nlwps_ctl = nv; 1987c478bd9Sstevel@tonic-gate return (0); 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 201ff19e029SMenno Lageman /*ARGSUSED*/ 202ff19e029SMenno Lageman static rctl_qty_t 203ff19e029SMenno Lageman task_nprocs_usage(rctl_t *r, proc_t *p) 204ff19e029SMenno Lageman { 205ff19e029SMenno Lageman task_t *t; 206ff19e029SMenno Lageman rctl_qty_t nprocs; 207ff19e029SMenno Lageman 208ff19e029SMenno Lageman ASSERT(MUTEX_HELD(&p->p_lock)); 209ff19e029SMenno Lageman 210ff19e029SMenno Lageman t = p->p_task; 211ff19e029SMenno Lageman mutex_enter(&p->p_zone->zone_nlwps_lock); 212ff19e029SMenno Lageman nprocs = t->tk_nprocs; 213ff19e029SMenno Lageman mutex_exit(&p->p_zone->zone_nlwps_lock); 214ff19e029SMenno Lageman 215ff19e029SMenno Lageman return (nprocs); 216ff19e029SMenno Lageman } 217ff19e029SMenno Lageman 218ff19e029SMenno Lageman /*ARGSUSED*/ 219ff19e029SMenno Lageman static int 220ff19e029SMenno Lageman task_nprocs_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, rctl_val_t *rcntl, 221ff19e029SMenno Lageman rctl_qty_t incr, uint_t flags) 222ff19e029SMenno Lageman { 223ff19e029SMenno Lageman rctl_qty_t nprocs; 224ff19e029SMenno Lageman 225ff19e029SMenno Lageman ASSERT(MUTEX_HELD(&p->p_lock)); 226ff19e029SMenno Lageman ASSERT(e->rcep_t == RCENTITY_TASK); 227ff19e029SMenno Lageman if (e->rcep_p.task == NULL) 228ff19e029SMenno Lageman return (0); 229ff19e029SMenno Lageman 230ff19e029SMenno Lageman ASSERT(MUTEX_HELD(&(e->rcep_p.task->tk_zone->zone_nlwps_lock))); 231ff19e029SMenno Lageman nprocs = e->rcep_p.task->tk_nprocs; 232ff19e029SMenno Lageman 233ff19e029SMenno Lageman if (nprocs + incr > rcntl->rcv_value) 234ff19e029SMenno Lageman return (1); 235ff19e029SMenno Lageman 236ff19e029SMenno Lageman return (0); 237ff19e029SMenno Lageman } 238ff19e029SMenno Lageman 239ff19e029SMenno Lageman /*ARGSUSED*/ 240ff19e029SMenno Lageman static int 241ff19e029SMenno Lageman task_nprocs_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e, 242ff19e029SMenno Lageman rctl_qty_t nv) { 243ff19e029SMenno Lageman 244ff19e029SMenno Lageman ASSERT(MUTEX_HELD(&p->p_lock)); 245ff19e029SMenno Lageman ASSERT(e->rcep_t == RCENTITY_TASK); 246ff19e029SMenno Lageman if (e->rcep_p.task == NULL) 247ff19e029SMenno Lageman return (0); 248ff19e029SMenno Lageman 249ff19e029SMenno Lageman e->rcep_p.task->tk_nprocs_ctl = nv; 250ff19e029SMenno Lageman return (0); 251ff19e029SMenno Lageman } 252ff19e029SMenno Lageman 2537c478bd9Sstevel@tonic-gate /* 2547c478bd9Sstevel@tonic-gate * static rctl_qty_t task_usage_cpu_secs(void *taskp) 2557c478bd9Sstevel@tonic-gate * 2567c478bd9Sstevel@tonic-gate * Overview 2577c478bd9Sstevel@tonic-gate * task_usage_cpu_secs() is the usage operation for the resource control 2587c478bd9Sstevel@tonic-gate * associated with the total accrued CPU seconds for a task. 2597c478bd9Sstevel@tonic-gate * 2607c478bd9Sstevel@tonic-gate * Return values 2617c478bd9Sstevel@tonic-gate * The number of CPU seconds consumed by the task is returned. 2627c478bd9Sstevel@tonic-gate * 2637c478bd9Sstevel@tonic-gate * Caller's context 2647c478bd9Sstevel@tonic-gate * The given task must be held across the call. 2657c478bd9Sstevel@tonic-gate */ 2667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2677c478bd9Sstevel@tonic-gate static rctl_qty_t 2687c478bd9Sstevel@tonic-gate task_cpu_time_usage(rctl_t *r, proc_t *p) 2697c478bd9Sstevel@tonic-gate { 2707c478bd9Sstevel@tonic-gate task_t *t = p->p_task; 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 2732850d85bSmv143129 return (t->tk_cpu_time); 2742850d85bSmv143129 } 2752850d85bSmv143129 2762850d85bSmv143129 /* 2772850d85bSmv143129 * int task_cpu_time_incr(task_t *t, rctl_qty_t incr) 2782850d85bSmv143129 * 2792850d85bSmv143129 * Overview 2802850d85bSmv143129 * task_cpu_time_incr() increments the amount of CPU time used 2812850d85bSmv143129 * by this task. 2822850d85bSmv143129 * 2832850d85bSmv143129 * Return values 2842850d85bSmv143129 * 1 if a second or more time is accumulated 2852850d85bSmv143129 * 0 otherwise 2862850d85bSmv143129 * 2872850d85bSmv143129 * Caller's context 2882850d85bSmv143129 * This is called by the clock tick accounting function to charge 2892850d85bSmv143129 * CPU time to a task. 2902850d85bSmv143129 */ 2912850d85bSmv143129 rctl_qty_t 2922850d85bSmv143129 task_cpu_time_incr(task_t *t, rctl_qty_t incr) 2932850d85bSmv143129 { 2942850d85bSmv143129 rctl_qty_t ret = 0; 2952850d85bSmv143129 2962850d85bSmv143129 mutex_enter(&t->tk_cpu_time_lock); 2972850d85bSmv143129 t->tk_cpu_ticks += incr; 2982850d85bSmv143129 if (t->tk_cpu_ticks >= hz) { 2992850d85bSmv143129 t->tk_cpu_time += t->tk_cpu_ticks / hz; 3002850d85bSmv143129 t->tk_cpu_ticks = t->tk_cpu_ticks % hz; 3012850d85bSmv143129 ret = t->tk_cpu_time; 3022850d85bSmv143129 } 3032850d85bSmv143129 mutex_exit(&t->tk_cpu_time_lock); 3042850d85bSmv143129 3052850d85bSmv143129 return (ret); 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* 3097c478bd9Sstevel@tonic-gate * static int task_test_cpu_secs(void *taskp, rctl_val_t *, int64_t incr, 3107c478bd9Sstevel@tonic-gate * int flags) 3117c478bd9Sstevel@tonic-gate * 3127c478bd9Sstevel@tonic-gate * Overview 3137c478bd9Sstevel@tonic-gate * task_test_cpu_secs() is the test-if-valid-increment for the resource 3147c478bd9Sstevel@tonic-gate * control for the total accrued CPU seconds for a task. 3157c478bd9Sstevel@tonic-gate * 3167c478bd9Sstevel@tonic-gate * Return values 3177c478bd9Sstevel@tonic-gate * 0 if the threshold limit was not passed, 1 if the limit was passed. 3187c478bd9Sstevel@tonic-gate * 3197c478bd9Sstevel@tonic-gate * Caller's context 3207c478bd9Sstevel@tonic-gate * The given task must be held across the call. 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3237c478bd9Sstevel@tonic-gate static int 3247c478bd9Sstevel@tonic-gate task_cpu_time_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e, 3257c478bd9Sstevel@tonic-gate struct rctl_val *rcntl, rctl_qty_t incr, uint_t flags) 3267c478bd9Sstevel@tonic-gate { 3277c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 3287c478bd9Sstevel@tonic-gate ASSERT(e->rcep_t == RCENTITY_TASK); 3297c478bd9Sstevel@tonic-gate if (e->rcep_p.task == NULL) 3307c478bd9Sstevel@tonic-gate return (0); 3317c478bd9Sstevel@tonic-gate 3322850d85bSmv143129 if (incr >= rcntl->rcv_value) 3337c478bd9Sstevel@tonic-gate return (1); 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate return (0); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate static task_t * 3397c478bd9Sstevel@tonic-gate task_find(taskid_t id, zoneid_t zoneid) 3407c478bd9Sstevel@tonic-gate { 3417c478bd9Sstevel@tonic-gate task_t *tk; 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&task_hash_lock)); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate if (mod_hash_find(task_hash, (mod_hash_key_t)(uintptr_t)id, 3467c478bd9Sstevel@tonic-gate (mod_hash_val_t *)&tk) == MH_ERR_NOTFOUND || 3477c478bd9Sstevel@tonic-gate (zoneid != ALL_ZONES && zoneid != tk->tk_zone->zone_id)) 3487c478bd9Sstevel@tonic-gate return (NULL); 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate return (tk); 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* 3547c478bd9Sstevel@tonic-gate * task_hold_by_id(), task_hold_by_id_zone() 3557c478bd9Sstevel@tonic-gate * 3567c478bd9Sstevel@tonic-gate * Overview 3577c478bd9Sstevel@tonic-gate * task_hold_by_id() is used to take a reference on a task by its task id, 3587c478bd9Sstevel@tonic-gate * supporting the various system call interfaces for obtaining resource data, 3597c478bd9Sstevel@tonic-gate * delivering signals, and so forth. 3607c478bd9Sstevel@tonic-gate * 3617c478bd9Sstevel@tonic-gate * Return values 3627c478bd9Sstevel@tonic-gate * Returns a pointer to the task_t with taskid_t id. The task is returned 3637c478bd9Sstevel@tonic-gate * with its hold count incremented by one. Returns NULL if there 3647c478bd9Sstevel@tonic-gate * is no task with the requested id. 3657c478bd9Sstevel@tonic-gate * 3667c478bd9Sstevel@tonic-gate * Caller's context 3677c478bd9Sstevel@tonic-gate * Caller must not be holding task_hash_lock. No restrictions on context. 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate task_t * 3707c478bd9Sstevel@tonic-gate task_hold_by_id_zone(taskid_t id, zoneid_t zoneid) 3717c478bd9Sstevel@tonic-gate { 3727c478bd9Sstevel@tonic-gate task_t *tk; 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate mutex_enter(&task_hash_lock); 3757c478bd9Sstevel@tonic-gate if ((tk = task_find(id, zoneid)) != NULL) 376*1a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&tk->tk_hold_count); 3777c478bd9Sstevel@tonic-gate mutex_exit(&task_hash_lock); 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate return (tk); 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate task_t * 3837c478bd9Sstevel@tonic-gate task_hold_by_id(taskid_t id) 3847c478bd9Sstevel@tonic-gate { 3857c478bd9Sstevel@tonic-gate zoneid_t zoneid; 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate if (INGLOBALZONE(curproc)) 3887c478bd9Sstevel@tonic-gate zoneid = ALL_ZONES; 3897c478bd9Sstevel@tonic-gate else 3907c478bd9Sstevel@tonic-gate zoneid = getzoneid(); 3917c478bd9Sstevel@tonic-gate return (task_hold_by_id_zone(id, zoneid)); 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* 3957c478bd9Sstevel@tonic-gate * void task_hold(task_t *) 3967c478bd9Sstevel@tonic-gate * 3977c478bd9Sstevel@tonic-gate * Overview 3987c478bd9Sstevel@tonic-gate * task_hold() is used to take an additional reference to the given task. 3997c478bd9Sstevel@tonic-gate * 4007c478bd9Sstevel@tonic-gate * Return values 4017c478bd9Sstevel@tonic-gate * None. 4027c478bd9Sstevel@tonic-gate * 4037c478bd9Sstevel@tonic-gate * Caller's context 4047c478bd9Sstevel@tonic-gate * No restriction on context. 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate void 4077c478bd9Sstevel@tonic-gate task_hold(task_t *tk) 4087c478bd9Sstevel@tonic-gate { 409*1a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&tk->tk_hold_count); 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * void task_rele(task_t *) 4147c478bd9Sstevel@tonic-gate * 4157c478bd9Sstevel@tonic-gate * Overview 4167c478bd9Sstevel@tonic-gate * task_rele() relinquishes a reference on the given task, which was acquired 4177c478bd9Sstevel@tonic-gate * via task_hold() or task_hold_by_id(). If this is the last member or 4187c478bd9Sstevel@tonic-gate * observer of the task, dispatch it for commitment via the accounting 4197c478bd9Sstevel@tonic-gate * subsystem. 4207c478bd9Sstevel@tonic-gate * 4217c478bd9Sstevel@tonic-gate * Return values 4227c478bd9Sstevel@tonic-gate * None. 4237c478bd9Sstevel@tonic-gate * 4247c478bd9Sstevel@tonic-gate * Caller's context 4257c478bd9Sstevel@tonic-gate * Caller must not be holding the task_hash_lock. 4267c478bd9Sstevel@tonic-gate */ 4277c478bd9Sstevel@tonic-gate void 4287c478bd9Sstevel@tonic-gate task_rele(task_t *tk) 4297c478bd9Sstevel@tonic-gate { 4307c478bd9Sstevel@tonic-gate mutex_enter(&task_hash_lock); 4317c478bd9Sstevel@tonic-gate if (atomic_add_32_nv(&tk->tk_hold_count, -1) > 0) { 4327c478bd9Sstevel@tonic-gate mutex_exit(&task_hash_lock); 4337c478bd9Sstevel@tonic-gate return; 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate 436ff19e029SMenno Lageman ASSERT(tk->tk_nprocs == 0); 437ff19e029SMenno Lageman 4387c478bd9Sstevel@tonic-gate mutex_enter(&tk->tk_zone->zone_nlwps_lock); 4397c478bd9Sstevel@tonic-gate tk->tk_proj->kpj_ntasks--; 4407c478bd9Sstevel@tonic-gate mutex_exit(&tk->tk_zone->zone_nlwps_lock); 4417c478bd9Sstevel@tonic-gate 442ff19e029SMenno Lageman task_kstat_delete(tk); 443ff19e029SMenno Lageman 4447c478bd9Sstevel@tonic-gate if (mod_hash_destroy(task_hash, 4457c478bd9Sstevel@tonic-gate (mod_hash_key_t)(uintptr_t)tk->tk_tkid) != 0) 4467c478bd9Sstevel@tonic-gate panic("unable to delete task %d", tk->tk_tkid); 4477c478bd9Sstevel@tonic-gate mutex_exit(&task_hash_lock); 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate /* 4507c478bd9Sstevel@tonic-gate * At this point, there are no members or observers of the task, so we 4517c478bd9Sstevel@tonic-gate * can safely send it on for commitment to the accounting subsystem. 4527c478bd9Sstevel@tonic-gate * The task will be destroyed in task_end() subsequent to commitment. 453ff19e029SMenno Lageman * Since we may be called with pidlock held, taskq_dispatch() cannot 454ff19e029SMenno Lageman * sleep. Commitment is handled by a backup thread in case dispatching 455ff19e029SMenno Lageman * the task fails. 4567c478bd9Sstevel@tonic-gate */ 457ff19e029SMenno Lageman if (taskq_dispatch(exacct_queue, exacct_commit_task, tk, 458ff19e029SMenno Lageman TQ_NOSLEEP | TQ_NOQUEUE) == NULL) { 459ff19e029SMenno Lageman mutex_enter(&task_commit_lock); 460ff19e029SMenno Lageman if (task_commit_head == NULL) { 461ff19e029SMenno Lageman task_commit_head = task_commit_tail = tk; 462ff19e029SMenno Lageman } else { 463ff19e029SMenno Lageman task_commit_tail->tk_commit_next = tk; 464ff19e029SMenno Lageman task_commit_tail = tk; 465ff19e029SMenno Lageman } 466ff19e029SMenno Lageman cv_signal(&task_commit_cv); 467ff19e029SMenno Lageman mutex_exit(&task_commit_lock); 468ff19e029SMenno Lageman } 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate /* 4727c478bd9Sstevel@tonic-gate * task_t *task_create(projid_t, zone *) 4737c478bd9Sstevel@tonic-gate * 4747c478bd9Sstevel@tonic-gate * Overview 4757c478bd9Sstevel@tonic-gate * A process constructing a new task calls task_create() to construct and 4767c478bd9Sstevel@tonic-gate * preinitialize the task for the appropriate destination project. Only one 4777c478bd9Sstevel@tonic-gate * task, the primordial task0, is not created with task_create(). 4787c478bd9Sstevel@tonic-gate * 4797c478bd9Sstevel@tonic-gate * Return values 4807c478bd9Sstevel@tonic-gate * None. 4817c478bd9Sstevel@tonic-gate * 4827c478bd9Sstevel@tonic-gate * Caller's context 4837c478bd9Sstevel@tonic-gate * Caller's context should be safe for KM_SLEEP allocations. 4847c478bd9Sstevel@tonic-gate * The caller should appropriately bump the kpj_ntasks counter on the 4857c478bd9Sstevel@tonic-gate * project that contains this task. 4867c478bd9Sstevel@tonic-gate */ 4877c478bd9Sstevel@tonic-gate task_t * 4887c478bd9Sstevel@tonic-gate task_create(projid_t projid, zone_t *zone) 4897c478bd9Sstevel@tonic-gate { 4907c478bd9Sstevel@tonic-gate task_t *tk = kmem_cache_alloc(task_cache, KM_SLEEP); 4917c478bd9Sstevel@tonic-gate task_t *ancestor_tk; 4927c478bd9Sstevel@tonic-gate taskid_t tkid; 4937c478bd9Sstevel@tonic-gate task_usage_t *tu = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 4947c478bd9Sstevel@tonic-gate mod_hash_hndl_t hndl; 4957c478bd9Sstevel@tonic-gate rctl_set_t *set = rctl_set_create(); 4967c478bd9Sstevel@tonic-gate rctl_alloc_gp_t *gp; 4977c478bd9Sstevel@tonic-gate rctl_entity_p_t e; 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate bzero(tk, sizeof (task_t)); 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate tk->tk_tkid = tkid = id_alloc(taskid_space); 5027c478bd9Sstevel@tonic-gate tk->tk_nlwps = 0; 5037c478bd9Sstevel@tonic-gate tk->tk_nlwps_ctl = INT_MAX; 504ff19e029SMenno Lageman tk->tk_nprocs = 0; 505ff19e029SMenno Lageman tk->tk_nprocs_ctl = INT_MAX; 5067c478bd9Sstevel@tonic-gate tk->tk_usage = tu; 5077eceb558Srh87107 tk->tk_inherited = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 508c97ad5cdSakolb tk->tk_proj = project_hold_by_id(projid, zone, PROJECT_HOLD_INSERT); 5097c478bd9Sstevel@tonic-gate tk->tk_flags = TASK_NORMAL; 510ff19e029SMenno Lageman tk->tk_commit_next = NULL; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate /* 5137c478bd9Sstevel@tonic-gate * Copy ancestor task's resource controls. 5147c478bd9Sstevel@tonic-gate */ 5157c478bd9Sstevel@tonic-gate zone_task_hold(zone); 5167c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 5177c478bd9Sstevel@tonic-gate ancestor_tk = curproc->p_task; 5187c478bd9Sstevel@tonic-gate task_hold(ancestor_tk); 5197c478bd9Sstevel@tonic-gate tk->tk_zone = zone; 5207c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate for (;;) { 5237c478bd9Sstevel@tonic-gate gp = rctl_set_dup_prealloc(ancestor_tk->tk_rctls); 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate mutex_enter(&ancestor_tk->tk_rctls->rcs_lock); 5267c478bd9Sstevel@tonic-gate if (rctl_set_dup_ready(ancestor_tk->tk_rctls, gp)) 5277c478bd9Sstevel@tonic-gate break; 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate mutex_exit(&ancestor_tk->tk_rctls->rcs_lock); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate rctl_prealloc_destroy(gp); 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate /* 5357c478bd9Sstevel@tonic-gate * At this point, curproc does not have the appropriate linkage 5367c478bd9Sstevel@tonic-gate * through the task to the project. So, rctl_set_dup should only 5377c478bd9Sstevel@tonic-gate * copy the rctls, and leave the callbacks for later. 5387c478bd9Sstevel@tonic-gate */ 5397c478bd9Sstevel@tonic-gate e.rcep_p.task = tk; 5407c478bd9Sstevel@tonic-gate e.rcep_t = RCENTITY_TASK; 5417c478bd9Sstevel@tonic-gate tk->tk_rctls = rctl_set_dup(ancestor_tk->tk_rctls, curproc, curproc, &e, 5427c478bd9Sstevel@tonic-gate set, gp, RCD_DUP); 5437c478bd9Sstevel@tonic-gate mutex_exit(&ancestor_tk->tk_rctls->rcs_lock); 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate rctl_prealloc_destroy(gp); 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate /* 5487c478bd9Sstevel@tonic-gate * Record the ancestor task's ID for use by extended accounting. 5497c478bd9Sstevel@tonic-gate */ 5507c478bd9Sstevel@tonic-gate tu->tu_anctaskid = ancestor_tk->tk_tkid; 5517c478bd9Sstevel@tonic-gate task_rele(ancestor_tk); 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate /* 5547c478bd9Sstevel@tonic-gate * Put new task structure in the hash table. 5557c478bd9Sstevel@tonic-gate */ 5567c478bd9Sstevel@tonic-gate (void) mod_hash_reserve(task_hash, &hndl); 5577c478bd9Sstevel@tonic-gate mutex_enter(&task_hash_lock); 558bb5ca623SVamsi Nagineni ASSERT(task_find(tkid, zone->zone_id) == NULL); 5597c478bd9Sstevel@tonic-gate if (mod_hash_insert_reserve(task_hash, (mod_hash_key_t)(uintptr_t)tkid, 5607c478bd9Sstevel@tonic-gate (mod_hash_val_t *)tk, hndl) != 0) { 5617c478bd9Sstevel@tonic-gate mod_hash_cancel(task_hash, &hndl); 5627c478bd9Sstevel@tonic-gate panic("unable to insert task %d(%p)", tkid, (void *)tk); 5637c478bd9Sstevel@tonic-gate } 5647c478bd9Sstevel@tonic-gate mutex_exit(&task_hash_lock); 5657c478bd9Sstevel@tonic-gate 566ff19e029SMenno Lageman tk->tk_nprocs_kstat = task_kstat_create(tk, zone); 5677c478bd9Sstevel@tonic-gate return (tk); 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate /* 5717c478bd9Sstevel@tonic-gate * void task_attach(task_t *, proc_t *) 5727c478bd9Sstevel@tonic-gate * 5737c478bd9Sstevel@tonic-gate * Overview 5747c478bd9Sstevel@tonic-gate * task_attach() is used to attach a process to a task; this operation is only 5757c478bd9Sstevel@tonic-gate * performed as a result of a fork() or settaskid() system call. The proc_t's 5767c478bd9Sstevel@tonic-gate * p_tasknext and p_taskprev fields will be set such that the proc_t is a 5777c478bd9Sstevel@tonic-gate * member of the doubly-linked list of proc_t's that make up the task. 5787c478bd9Sstevel@tonic-gate * 5797c478bd9Sstevel@tonic-gate * Return values 5807c478bd9Sstevel@tonic-gate * None. 5817c478bd9Sstevel@tonic-gate * 5827c478bd9Sstevel@tonic-gate * Caller's context 5837c478bd9Sstevel@tonic-gate * pidlock and p->p_lock must be held on entry. 5847c478bd9Sstevel@tonic-gate */ 5857c478bd9Sstevel@tonic-gate void 5867c478bd9Sstevel@tonic-gate task_attach(task_t *tk, proc_t *p) 5877c478bd9Sstevel@tonic-gate { 5887c478bd9Sstevel@tonic-gate proc_t *first, *prev; 5897c478bd9Sstevel@tonic-gate ASSERT(tk != NULL); 5907c478bd9Sstevel@tonic-gate ASSERT(p != NULL); 5917c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 5927c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate if (tk->tk_memb_list == NULL) { 5957c478bd9Sstevel@tonic-gate p->p_tasknext = p; 5967c478bd9Sstevel@tonic-gate p->p_taskprev = p; 5977c478bd9Sstevel@tonic-gate } else { 5987c478bd9Sstevel@tonic-gate first = tk->tk_memb_list; 5997c478bd9Sstevel@tonic-gate prev = first->p_taskprev; 6007c478bd9Sstevel@tonic-gate first->p_taskprev = p; 6017c478bd9Sstevel@tonic-gate p->p_tasknext = first; 6027c478bd9Sstevel@tonic-gate p->p_taskprev = prev; 6037c478bd9Sstevel@tonic-gate prev->p_tasknext = p; 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate tk->tk_memb_list = p; 6067c478bd9Sstevel@tonic-gate task_hold(tk); 6077c478bd9Sstevel@tonic-gate p->p_task = tk; 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate /* 6117c478bd9Sstevel@tonic-gate * task_begin() 6127c478bd9Sstevel@tonic-gate * 6137c478bd9Sstevel@tonic-gate * Overview 6147c478bd9Sstevel@tonic-gate * A process constructing a new task calls task_begin() to initialize the 6157c478bd9Sstevel@tonic-gate * task, by attaching itself as a member. 6167c478bd9Sstevel@tonic-gate * 6177c478bd9Sstevel@tonic-gate * Return values 6187c478bd9Sstevel@tonic-gate * None. 6197c478bd9Sstevel@tonic-gate * 6207c478bd9Sstevel@tonic-gate * Caller's context 6217c478bd9Sstevel@tonic-gate * pidlock and p_lock must be held across the call to task_begin(). 6227c478bd9Sstevel@tonic-gate */ 6237c478bd9Sstevel@tonic-gate void 6247c478bd9Sstevel@tonic-gate task_begin(task_t *tk, proc_t *p) 6257c478bd9Sstevel@tonic-gate { 6267c478bd9Sstevel@tonic-gate timestruc_t ts; 6277c478bd9Sstevel@tonic-gate task_usage_t *tu; 628ff19e029SMenno Lageman rctl_entity_p_t e; 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 6317c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate mutex_enter(&tk->tk_usage_lock); 6347c478bd9Sstevel@tonic-gate tu = tk->tk_usage; 6357c478bd9Sstevel@tonic-gate gethrestime(&ts); 6367c478bd9Sstevel@tonic-gate tu->tu_startsec = (uint64_t)ts.tv_sec; 6377c478bd9Sstevel@tonic-gate tu->tu_startnsec = (uint64_t)ts.tv_nsec; 6387c478bd9Sstevel@tonic-gate mutex_exit(&tk->tk_usage_lock); 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /* 6417c478bd9Sstevel@tonic-gate * Join process to the task as a member. 6427c478bd9Sstevel@tonic-gate */ 6437c478bd9Sstevel@tonic-gate task_attach(tk, p); 644ff19e029SMenno Lageman 645ff19e029SMenno Lageman /* 646ff19e029SMenno Lageman * Now that the linkage from process to task is complete, do the 647ff19e029SMenno Lageman * required callback for the task rctl set. 648ff19e029SMenno Lageman */ 649ff19e029SMenno Lageman e.rcep_p.task = tk; 650ff19e029SMenno Lageman e.rcep_t = RCENTITY_TASK; 651ff19e029SMenno Lageman (void) rctl_set_dup(NULL, NULL, p, &e, tk->tk_rctls, NULL, 652ff19e029SMenno Lageman RCD_CALLBACK); 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* 6567c478bd9Sstevel@tonic-gate * void task_detach(proc_t *) 6577c478bd9Sstevel@tonic-gate * 6587c478bd9Sstevel@tonic-gate * Overview 6597c478bd9Sstevel@tonic-gate * task_detach() removes the specified process from its task. task_detach 6607c478bd9Sstevel@tonic-gate * sets the process's task membership to NULL, in anticipation of a final exit 6617c478bd9Sstevel@tonic-gate * or of joining a new task. Because task_rele() requires a context safe for 6627c478bd9Sstevel@tonic-gate * KM_SLEEP allocations, a task_detach() is followed by a subsequent 6637c478bd9Sstevel@tonic-gate * task_rele() once appropriate context is available. 6647c478bd9Sstevel@tonic-gate * 6657c478bd9Sstevel@tonic-gate * Because task_detach() involves relinquishing the process's membership in 6667c478bd9Sstevel@tonic-gate * the project, any observational rctls the process may have had on the task 6677c478bd9Sstevel@tonic-gate * or project are destroyed. 6687c478bd9Sstevel@tonic-gate * 6697c478bd9Sstevel@tonic-gate * Return values 6707c478bd9Sstevel@tonic-gate * None. 6717c478bd9Sstevel@tonic-gate * 6727c478bd9Sstevel@tonic-gate * Caller's context 6737c478bd9Sstevel@tonic-gate * pidlock and p_lock held across task_detach(). 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate void 6767c478bd9Sstevel@tonic-gate task_detach(proc_t *p) 6777c478bd9Sstevel@tonic-gate { 6787c478bd9Sstevel@tonic-gate task_t *tk = p->p_task; 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 6817c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 6827c478bd9Sstevel@tonic-gate ASSERT(p->p_task != NULL); 6837c478bd9Sstevel@tonic-gate ASSERT(tk->tk_memb_list != NULL); 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate if (tk->tk_memb_list == p) 6867c478bd9Sstevel@tonic-gate tk->tk_memb_list = p->p_tasknext; 6877c478bd9Sstevel@tonic-gate if (tk->tk_memb_list == p) 6887c478bd9Sstevel@tonic-gate tk->tk_memb_list = NULL; 6897c478bd9Sstevel@tonic-gate p->p_taskprev->p_tasknext = p->p_tasknext; 6907c478bd9Sstevel@tonic-gate p->p_tasknext->p_taskprev = p->p_taskprev; 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate rctl_set_tearoff(p->p_task->tk_rctls, p); 6937c478bd9Sstevel@tonic-gate rctl_set_tearoff(p->p_task->tk_proj->kpj_rctls, p); 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate p->p_task = NULL; 6967c478bd9Sstevel@tonic-gate p->p_tasknext = p->p_taskprev = NULL; 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate /* 7007c478bd9Sstevel@tonic-gate * task_change(task_t *, proc_t *) 7017c478bd9Sstevel@tonic-gate * 7027c478bd9Sstevel@tonic-gate * Overview 7037c478bd9Sstevel@tonic-gate * task_change() removes the specified process from its current task. The 7047c478bd9Sstevel@tonic-gate * process is then attached to the specified task. This routine is called 7057c478bd9Sstevel@tonic-gate * from settaskid() when process is being moved to a new task. 7067c478bd9Sstevel@tonic-gate * 7077c478bd9Sstevel@tonic-gate * Return values 7087c478bd9Sstevel@tonic-gate * None. 7097c478bd9Sstevel@tonic-gate * 7107c478bd9Sstevel@tonic-gate * Caller's context 7117c478bd9Sstevel@tonic-gate * pidlock and p_lock held across task_change() 7127c478bd9Sstevel@tonic-gate */ 7137c478bd9Sstevel@tonic-gate void 7147c478bd9Sstevel@tonic-gate task_change(task_t *newtk, proc_t *p) 7157c478bd9Sstevel@tonic-gate { 7167c478bd9Sstevel@tonic-gate task_t *oldtk = p->p_task; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 7197c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 7207c478bd9Sstevel@tonic-gate ASSERT(oldtk != NULL); 7217c478bd9Sstevel@tonic-gate ASSERT(oldtk->tk_memb_list != NULL); 7227c478bd9Sstevel@tonic-gate 723bb5ca623SVamsi Nagineni mutex_enter(&oldtk->tk_zone->zone_nlwps_lock); 7247c478bd9Sstevel@tonic-gate oldtk->tk_nlwps -= p->p_lwpcnt; 725ff19e029SMenno Lageman oldtk->tk_nprocs--; 726bb5ca623SVamsi Nagineni mutex_exit(&oldtk->tk_zone->zone_nlwps_lock); 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate mutex_enter(&newtk->tk_zone->zone_nlwps_lock); 7297c478bd9Sstevel@tonic-gate newtk->tk_nlwps += p->p_lwpcnt; 730ff19e029SMenno Lageman newtk->tk_nprocs++; 7317c478bd9Sstevel@tonic-gate mutex_exit(&newtk->tk_zone->zone_nlwps_lock); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate task_detach(p); 7347c478bd9Sstevel@tonic-gate task_begin(newtk, p); 7357eceb558Srh87107 exacct_move_mstate(p, oldtk, newtk); 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate /* 7397c478bd9Sstevel@tonic-gate * task_end() 7407c478bd9Sstevel@tonic-gate * 7417c478bd9Sstevel@tonic-gate * Overview 7427c478bd9Sstevel@tonic-gate * task_end() contains the actions executed once the final member of 7437c478bd9Sstevel@tonic-gate * a task has released the task, and all actions connected with the task, such 7447c478bd9Sstevel@tonic-gate * as committing an accounting record to a file, are completed. It is called 7457c478bd9Sstevel@tonic-gate * by the known last consumer of the task information. Additionally, 7467c478bd9Sstevel@tonic-gate * task_end() must never refer to any process in the system. 7477c478bd9Sstevel@tonic-gate * 7487c478bd9Sstevel@tonic-gate * Return values 7497c478bd9Sstevel@tonic-gate * None. 7507c478bd9Sstevel@tonic-gate * 7517c478bd9Sstevel@tonic-gate * Caller's context 7527c478bd9Sstevel@tonic-gate * No restrictions on context, beyond that given above. 7537c478bd9Sstevel@tonic-gate */ 7547c478bd9Sstevel@tonic-gate void 7557c478bd9Sstevel@tonic-gate task_end(task_t *tk) 7567c478bd9Sstevel@tonic-gate { 7577c478bd9Sstevel@tonic-gate ASSERT(tk->tk_hold_count == 0); 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate project_rele(tk->tk_proj); 7607c478bd9Sstevel@tonic-gate kmem_free(tk->tk_usage, sizeof (task_usage_t)); 7617eceb558Srh87107 kmem_free(tk->tk_inherited, sizeof (task_usage_t)); 7627c478bd9Sstevel@tonic-gate if (tk->tk_prevusage != NULL) 7637c478bd9Sstevel@tonic-gate kmem_free(tk->tk_prevusage, sizeof (task_usage_t)); 7647c478bd9Sstevel@tonic-gate if (tk->tk_zoneusage != NULL) 7657c478bd9Sstevel@tonic-gate kmem_free(tk->tk_zoneusage, sizeof (task_usage_t)); 7667c478bd9Sstevel@tonic-gate rctl_set_free(tk->tk_rctls); 7677c478bd9Sstevel@tonic-gate id_free(taskid_space, tk->tk_tkid); 7687c478bd9Sstevel@tonic-gate zone_task_rele(tk->tk_zone); 7697c478bd9Sstevel@tonic-gate kmem_cache_free(task_cache, tk); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate static void 7737c478bd9Sstevel@tonic-gate changeproj(proc_t *p, kproject_t *kpj, zone_t *zone, void *projbuf, 7747c478bd9Sstevel@tonic-gate void *zonebuf) 7757c478bd9Sstevel@tonic-gate { 7767c478bd9Sstevel@tonic-gate kproject_t *oldkpj; 7777c478bd9Sstevel@tonic-gate kthread_t *t; 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 7807c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate if ((t = p->p_tlist) != NULL) { 7837c478bd9Sstevel@tonic-gate do { 7847c478bd9Sstevel@tonic-gate (void) project_hold(kpj); 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate thread_lock(t); 7877c478bd9Sstevel@tonic-gate oldkpj = ttoproj(t); 788c97ad5cdSakolb 789c97ad5cdSakolb /* 790c97ad5cdSakolb * Kick this thread so that he doesn't sit 791c97ad5cdSakolb * on a wrong wait queue. 792c97ad5cdSakolb */ 793c97ad5cdSakolb if (ISWAITING(t)) 794c97ad5cdSakolb setrun_locked(t); 795c97ad5cdSakolb 796c97ad5cdSakolb /* 797c97ad5cdSakolb * The thread wants to go on the project wait queue, but 798c97ad5cdSakolb * the waitq is changing. 799c97ad5cdSakolb */ 800c97ad5cdSakolb if (t->t_schedflag & TS_PROJWAITQ) 801c97ad5cdSakolb t->t_schedflag &= ~ TS_PROJWAITQ; 802c97ad5cdSakolb 8037c478bd9Sstevel@tonic-gate t->t_proj = kpj; 8047c478bd9Sstevel@tonic-gate t->t_pre_sys = 1; /* For cred update */ 8057c478bd9Sstevel@tonic-gate thread_unlock(t); 8067c478bd9Sstevel@tonic-gate fss_changeproj(t, kpj, zone, projbuf, zonebuf); 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate project_rele(oldkpj); 8097c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist); 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate /* 8147c478bd9Sstevel@tonic-gate * task_join() 8157c478bd9Sstevel@tonic-gate * 8167c478bd9Sstevel@tonic-gate * Overview 8177c478bd9Sstevel@tonic-gate * task_join() contains the actions that must be executed when the first 8187c478bd9Sstevel@tonic-gate * member (curproc) of a newly created task joins it. It may never fail. 8197c478bd9Sstevel@tonic-gate * 8207c478bd9Sstevel@tonic-gate * The caller must make sure holdlwps() is called so that all other lwps are 8217c478bd9Sstevel@tonic-gate * stopped prior to calling this function. 8227c478bd9Sstevel@tonic-gate * 8237c478bd9Sstevel@tonic-gate * NB: It returns with curproc->p_lock held. 8247c478bd9Sstevel@tonic-gate * 8257c478bd9Sstevel@tonic-gate * Return values 8267c478bd9Sstevel@tonic-gate * Pointer to the old task. 8277c478bd9Sstevel@tonic-gate * 8287c478bd9Sstevel@tonic-gate * Caller's context 8297c478bd9Sstevel@tonic-gate * cpu_lock must be held entering the function. It will acquire pidlock, 8307c478bd9Sstevel@tonic-gate * p_crlock and p_lock during execution. 8317c478bd9Sstevel@tonic-gate */ 8327c478bd9Sstevel@tonic-gate task_t * 8337c478bd9Sstevel@tonic-gate task_join(task_t *tk, uint_t flags) 8347c478bd9Sstevel@tonic-gate { 8357c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 8367c478bd9Sstevel@tonic-gate task_t *prev_tk; 8377c478bd9Sstevel@tonic-gate void *projbuf, *zonebuf; 8387c478bd9Sstevel@tonic-gate zone_t *zone = tk->tk_zone; 8397c478bd9Sstevel@tonic-gate projid_t projid = tk->tk_proj->kpj_id; 8407c478bd9Sstevel@tonic-gate cred_t *oldcr; 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate /* 8437c478bd9Sstevel@tonic-gate * We can't know for sure if holdlwps() was called, but we can check to 8447c478bd9Sstevel@tonic-gate * ensure we're single-threaded. 8457c478bd9Sstevel@tonic-gate */ 8467c478bd9Sstevel@tonic-gate ASSERT(curthread == p->p_agenttp || p->p_lwprcnt == 1); 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate /* 8497c478bd9Sstevel@tonic-gate * Changing the credential is always hard because we cannot 8507c478bd9Sstevel@tonic-gate * allocate memory when holding locks but we don't know whether 8517c478bd9Sstevel@tonic-gate * we need to change it. We first get a reference to the current 8527c478bd9Sstevel@tonic-gate * cred if we need to change it. Then we create a credential 8537c478bd9Sstevel@tonic-gate * with an updated project id. Finally we install it, first 8547c478bd9Sstevel@tonic-gate * releasing the reference we had on the p_cred at the time we 8557c478bd9Sstevel@tonic-gate * acquired the lock the first time and later we release the 8567c478bd9Sstevel@tonic-gate * reference to p_cred at the time we acquired the lock the 8577c478bd9Sstevel@tonic-gate * second time. 8587c478bd9Sstevel@tonic-gate */ 8597c478bd9Sstevel@tonic-gate mutex_enter(&p->p_crlock); 8607c478bd9Sstevel@tonic-gate if (crgetprojid(p->p_cred) == projid) 8617c478bd9Sstevel@tonic-gate oldcr = NULL; 8627c478bd9Sstevel@tonic-gate else 8637c478bd9Sstevel@tonic-gate crhold(oldcr = p->p_cred); 8647c478bd9Sstevel@tonic-gate mutex_exit(&p->p_crlock); 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate if (oldcr != NULL) { 8677c478bd9Sstevel@tonic-gate cred_t *newcr = crdup(oldcr); 8687c478bd9Sstevel@tonic-gate crsetprojid(newcr, projid); 8697c478bd9Sstevel@tonic-gate crfree(oldcr); 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate mutex_enter(&p->p_crlock); 8727c478bd9Sstevel@tonic-gate oldcr = p->p_cred; 8737c478bd9Sstevel@tonic-gate p->p_cred = newcr; 8747c478bd9Sstevel@tonic-gate mutex_exit(&p->p_crlock); 8757c478bd9Sstevel@tonic-gate crfree(oldcr); 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate /* 8797c478bd9Sstevel@tonic-gate * Make sure that the number of processor sets is constant 8807c478bd9Sstevel@tonic-gate * across this operation. 8817c478bd9Sstevel@tonic-gate */ 8827c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate projbuf = fss_allocbuf(FSS_NPSET_BUF, FSS_ALLOC_PROJ); 8857c478bd9Sstevel@tonic-gate zonebuf = fss_allocbuf(FSS_NPSET_BUF, FSS_ALLOC_ZONE); 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 8887c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate prev_tk = p->p_task; 8917c478bd9Sstevel@tonic-gate task_change(tk, p); 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate /* 8947c478bd9Sstevel@tonic-gate * Now move threads one by one to their new project. 8957c478bd9Sstevel@tonic-gate */ 8967c478bd9Sstevel@tonic-gate changeproj(p, tk->tk_proj, zone, projbuf, zonebuf); 8977c478bd9Sstevel@tonic-gate if (flags & TASK_FINAL) 8987c478bd9Sstevel@tonic-gate p->p_task->tk_flags |= TASK_FINAL; 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate fss_freebuf(zonebuf, FSS_ALLOC_ZONE); 9037c478bd9Sstevel@tonic-gate fss_freebuf(projbuf, FSS_ALLOC_PROJ); 9047c478bd9Sstevel@tonic-gate return (prev_tk); 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate /* 9087c478bd9Sstevel@tonic-gate * rctl ops vectors 9097c478bd9Sstevel@tonic-gate */ 9107c478bd9Sstevel@tonic-gate static rctl_ops_t task_lwps_ops = { 9117c478bd9Sstevel@tonic-gate rcop_no_action, 9127c478bd9Sstevel@tonic-gate task_lwps_usage, 9137c478bd9Sstevel@tonic-gate task_lwps_set, 9147c478bd9Sstevel@tonic-gate task_lwps_test 9157c478bd9Sstevel@tonic-gate }; 9167c478bd9Sstevel@tonic-gate 917ff19e029SMenno Lageman static rctl_ops_t task_procs_ops = { 918ff19e029SMenno Lageman rcop_no_action, 919ff19e029SMenno Lageman task_nprocs_usage, 920ff19e029SMenno Lageman task_nprocs_set, 921ff19e029SMenno Lageman task_nprocs_test 922ff19e029SMenno Lageman }; 923ff19e029SMenno Lageman 9247c478bd9Sstevel@tonic-gate static rctl_ops_t task_cpu_time_ops = { 9257c478bd9Sstevel@tonic-gate rcop_no_action, 9267c478bd9Sstevel@tonic-gate task_cpu_time_usage, 9277c478bd9Sstevel@tonic-gate rcop_no_set, 9287c478bd9Sstevel@tonic-gate task_cpu_time_test 9297c478bd9Sstevel@tonic-gate }; 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9327c478bd9Sstevel@tonic-gate /* 9337c478bd9Sstevel@tonic-gate * void task_init(void) 9347c478bd9Sstevel@tonic-gate * 9357c478bd9Sstevel@tonic-gate * Overview 9367c478bd9Sstevel@tonic-gate * task_init() initializes task-related hashes, caches, and the task id 9377c478bd9Sstevel@tonic-gate * space. Additionally, task_init() establishes p0 as a member of task0. 9387c478bd9Sstevel@tonic-gate * Called by main(). 9397c478bd9Sstevel@tonic-gate * 9407c478bd9Sstevel@tonic-gate * Return values 9417c478bd9Sstevel@tonic-gate * None. 9427c478bd9Sstevel@tonic-gate * 9437c478bd9Sstevel@tonic-gate * Caller's context 9447c478bd9Sstevel@tonic-gate * task_init() must be called prior to MP startup. 9457c478bd9Sstevel@tonic-gate */ 9467c478bd9Sstevel@tonic-gate void 9477c478bd9Sstevel@tonic-gate task_init(void) 9487c478bd9Sstevel@tonic-gate { 9497c478bd9Sstevel@tonic-gate proc_t *p = &p0; 9507c478bd9Sstevel@tonic-gate mod_hash_hndl_t hndl; 9517c478bd9Sstevel@tonic-gate rctl_set_t *set; 9527c478bd9Sstevel@tonic-gate rctl_alloc_gp_t *gp; 9537c478bd9Sstevel@tonic-gate rctl_entity_p_t e; 954ff19e029SMenno Lageman 9557c478bd9Sstevel@tonic-gate /* 9567c478bd9Sstevel@tonic-gate * Initialize task_cache and taskid_space. 9577c478bd9Sstevel@tonic-gate */ 9587c478bd9Sstevel@tonic-gate task_cache = kmem_cache_create("task_cache", sizeof (task_t), 9597c478bd9Sstevel@tonic-gate 0, NULL, NULL, NULL, NULL, NULL, 0); 9607c478bd9Sstevel@tonic-gate taskid_space = id_space_create("taskid_space", 0, MAX_TASKID); 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate /* 9637c478bd9Sstevel@tonic-gate * Initialize task hash table. 9647c478bd9Sstevel@tonic-gate */ 9657c478bd9Sstevel@tonic-gate task_hash = mod_hash_create_idhash("task_hash", task_hash_size, 9667c478bd9Sstevel@tonic-gate mod_hash_null_valdtor); 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate /* 9697c478bd9Sstevel@tonic-gate * Initialize task-based rctls. 9707c478bd9Sstevel@tonic-gate */ 9717c478bd9Sstevel@tonic-gate rc_task_lwps = rctl_register("task.max-lwps", RCENTITY_TASK, 9727c478bd9Sstevel@tonic-gate RCTL_GLOBAL_NOACTION | RCTL_GLOBAL_COUNT, INT_MAX, INT_MAX, 9737c478bd9Sstevel@tonic-gate &task_lwps_ops); 974ff19e029SMenno Lageman rc_task_nprocs = rctl_register("task.max-processes", RCENTITY_TASK, 975ff19e029SMenno Lageman RCTL_GLOBAL_NOACTION | RCTL_GLOBAL_COUNT, INT_MAX, INT_MAX, 976ff19e029SMenno Lageman &task_procs_ops); 9777c478bd9Sstevel@tonic-gate rc_task_cpu_time = rctl_register("task.max-cpu-time", RCENTITY_TASK, 9787c478bd9Sstevel@tonic-gate RCTL_GLOBAL_NOACTION | RCTL_GLOBAL_DENY_NEVER | 9797c478bd9Sstevel@tonic-gate RCTL_GLOBAL_CPU_TIME | RCTL_GLOBAL_INFINITE | 9807c478bd9Sstevel@tonic-gate RCTL_GLOBAL_UNOBSERVABLE | RCTL_GLOBAL_SECONDS, UINT64_MAX, 9817c478bd9Sstevel@tonic-gate UINT64_MAX, &task_cpu_time_ops); 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate /* 9847c478bd9Sstevel@tonic-gate * Create task0 and place p0 in it as a member. 9857c478bd9Sstevel@tonic-gate */ 9867c478bd9Sstevel@tonic-gate task0p = kmem_cache_alloc(task_cache, KM_SLEEP); 9877c478bd9Sstevel@tonic-gate bzero(task0p, sizeof (task_t)); 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate task0p->tk_tkid = id_alloc(taskid_space); 9907c478bd9Sstevel@tonic-gate task0p->tk_usage = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 9917eceb558Srh87107 task0p->tk_inherited = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP); 9920209230bSgjelinek task0p->tk_proj = project_hold_by_id(0, &zone0, 9937c478bd9Sstevel@tonic-gate PROJECT_HOLD_INSERT); 9947c478bd9Sstevel@tonic-gate task0p->tk_flags = TASK_NORMAL; 9957c478bd9Sstevel@tonic-gate task0p->tk_nlwps = p->p_lwpcnt; 996ff19e029SMenno Lageman task0p->tk_nprocs = 1; 9977c478bd9Sstevel@tonic-gate task0p->tk_zone = global_zone; 998ff19e029SMenno Lageman task0p->tk_commit_next = NULL; 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate set = rctl_set_create(); 10017c478bd9Sstevel@tonic-gate gp = rctl_set_init_prealloc(RCENTITY_TASK); 10027c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 10037c478bd9Sstevel@tonic-gate e.rcep_p.task = task0p; 10047c478bd9Sstevel@tonic-gate e.rcep_t = RCENTITY_TASK; 10057c478bd9Sstevel@tonic-gate task0p->tk_rctls = rctl_set_init(RCENTITY_TASK, curproc, &e, set, gp); 10067c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 10077c478bd9Sstevel@tonic-gate rctl_prealloc_destroy(gp); 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate (void) mod_hash_reserve(task_hash, &hndl); 10107c478bd9Sstevel@tonic-gate mutex_enter(&task_hash_lock); 10117c478bd9Sstevel@tonic-gate ASSERT(task_find(task0p->tk_tkid, GLOBAL_ZONEID) == NULL); 10127c478bd9Sstevel@tonic-gate if (mod_hash_insert_reserve(task_hash, 10137c478bd9Sstevel@tonic-gate (mod_hash_key_t)(uintptr_t)task0p->tk_tkid, 10147c478bd9Sstevel@tonic-gate (mod_hash_val_t *)task0p, hndl) != 0) { 10157c478bd9Sstevel@tonic-gate mod_hash_cancel(task_hash, &hndl); 10167c478bd9Sstevel@tonic-gate panic("unable to insert task %d(%p)", task0p->tk_tkid, 10177c478bd9Sstevel@tonic-gate (void *)task0p); 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate mutex_exit(&task_hash_lock); 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate task0p->tk_memb_list = p; 10227c478bd9Sstevel@tonic-gate 1023ff19e029SMenno Lageman task0p->tk_nprocs_kstat = task_kstat_create(task0p, task0p->tk_zone); 1024ff19e029SMenno Lageman 10257c478bd9Sstevel@tonic-gate /* 10267c478bd9Sstevel@tonic-gate * Initialize task pointers for p0, including doubly linked list of task 10277c478bd9Sstevel@tonic-gate * members. 10287c478bd9Sstevel@tonic-gate */ 10297c478bd9Sstevel@tonic-gate p->p_task = task0p; 10307c478bd9Sstevel@tonic-gate p->p_taskprev = p->p_tasknext = p; 10317c478bd9Sstevel@tonic-gate task_hold(task0p); 10327c478bd9Sstevel@tonic-gate } 1033ff19e029SMenno Lageman 1034ff19e029SMenno Lageman static int 1035ff19e029SMenno Lageman task_nprocs_kstat_update(kstat_t *ksp, int rw) 1036ff19e029SMenno Lageman { 1037ff19e029SMenno Lageman task_t *tk = ksp->ks_private; 1038ff19e029SMenno Lageman task_kstat_t *ktk = ksp->ks_data; 1039ff19e029SMenno Lageman 1040ff19e029SMenno Lageman if (rw == KSTAT_WRITE) 1041ff19e029SMenno Lageman return (EACCES); 1042ff19e029SMenno Lageman 1043ff19e029SMenno Lageman ktk->ktk_usage.value.ui64 = tk->tk_nprocs; 1044ff19e029SMenno Lageman ktk->ktk_value.value.ui64 = tk->tk_nprocs_ctl; 1045ff19e029SMenno Lageman return (0); 1046ff19e029SMenno Lageman } 1047ff19e029SMenno Lageman 1048ff19e029SMenno Lageman static kstat_t * 1049ff19e029SMenno Lageman task_kstat_create(task_t *tk, zone_t *zone) 1050ff19e029SMenno Lageman { 1051ff19e029SMenno Lageman kstat_t *ksp; 1052ff19e029SMenno Lageman task_kstat_t *ktk; 1053ff19e029SMenno Lageman char *zonename = zone->zone_name; 1054ff19e029SMenno Lageman 1055ff19e029SMenno Lageman ksp = rctl_kstat_create_task(tk, "nprocs", KSTAT_TYPE_NAMED, 1056ff19e029SMenno Lageman sizeof (task_kstat_t) / sizeof (kstat_named_t), 1057ff19e029SMenno Lageman KSTAT_FLAG_VIRTUAL); 1058ff19e029SMenno Lageman 1059ff19e029SMenno Lageman if (ksp == NULL) 1060ff19e029SMenno Lageman return (NULL); 1061ff19e029SMenno Lageman 1062ff19e029SMenno Lageman ktk = ksp->ks_data = kmem_alloc(sizeof (task_kstat_t), KM_SLEEP); 1063ff19e029SMenno Lageman ksp->ks_data_size += strlen(zonename) + 1; 1064ff19e029SMenno Lageman kstat_named_init(&ktk->ktk_zonename, "zonename", KSTAT_DATA_STRING); 1065ff19e029SMenno Lageman kstat_named_setstr(&ktk->ktk_zonename, zonename); 1066ff19e029SMenno Lageman kstat_named_init(&ktk->ktk_usage, "usage", KSTAT_DATA_UINT64); 1067ff19e029SMenno Lageman kstat_named_init(&ktk->ktk_value, "value", KSTAT_DATA_UINT64); 1068ff19e029SMenno Lageman ksp->ks_update = task_nprocs_kstat_update; 1069ff19e029SMenno Lageman ksp->ks_private = tk; 1070ff19e029SMenno Lageman kstat_install(ksp); 1071ff19e029SMenno Lageman 1072ff19e029SMenno Lageman return (ksp); 1073ff19e029SMenno Lageman } 1074ff19e029SMenno Lageman 1075ff19e029SMenno Lageman static void 1076ff19e029SMenno Lageman task_kstat_delete(task_t *tk) 1077ff19e029SMenno Lageman { 1078ff19e029SMenno Lageman void *data; 1079ff19e029SMenno Lageman 1080ff19e029SMenno Lageman if (tk->tk_nprocs_kstat != NULL) { 1081ff19e029SMenno Lageman data = tk->tk_nprocs_kstat->ks_data; 1082ff19e029SMenno Lageman kstat_delete(tk->tk_nprocs_kstat); 1083ff19e029SMenno Lageman kmem_free(data, sizeof (task_kstat_t)); 1084ff19e029SMenno Lageman tk->tk_nprocs_kstat = NULL; 1085ff19e029SMenno Lageman } 1086ff19e029SMenno Lageman } 1087ff19e029SMenno Lageman 1088ff19e029SMenno Lageman void 1089ff19e029SMenno Lageman task_commit_thread_init() 1090ff19e029SMenno Lageman { 1091ff19e029SMenno Lageman mutex_init(&task_commit_lock, NULL, MUTEX_DEFAULT, NULL); 1092ff19e029SMenno Lageman cv_init(&task_commit_cv, NULL, CV_DEFAULT, NULL); 1093ff19e029SMenno Lageman task_commit_thread = thread_create(NULL, 0, task_commit, NULL, 0, 1094ff19e029SMenno Lageman &p0, TS_RUN, minclsyspri); 1095ff19e029SMenno Lageman } 1096ff19e029SMenno Lageman 1097ff19e029SMenno Lageman /* 1098ff19e029SMenno Lageman * Backup thread to commit task resource usage when taskq_dispatch() fails. 1099ff19e029SMenno Lageman */ 1100ff19e029SMenno Lageman static void 1101ff19e029SMenno Lageman task_commit() 1102ff19e029SMenno Lageman { 1103ff19e029SMenno Lageman callb_cpr_t cprinfo; 1104ff19e029SMenno Lageman 1105ff19e029SMenno Lageman CALLB_CPR_INIT(&cprinfo, &task_commit_lock, callb_generic_cpr, 1106ff19e029SMenno Lageman "task_commit_thread"); 1107ff19e029SMenno Lageman 1108ff19e029SMenno Lageman mutex_enter(&task_commit_lock); 1109ff19e029SMenno Lageman 1110ff19e029SMenno Lageman for (;;) { 1111ff19e029SMenno Lageman while (task_commit_head == NULL) { 1112ff19e029SMenno Lageman CALLB_CPR_SAFE_BEGIN(&cprinfo); 1113ff19e029SMenno Lageman cv_wait(&task_commit_cv, &task_commit_lock); 1114ff19e029SMenno Lageman CALLB_CPR_SAFE_END(&cprinfo, &task_commit_lock); 1115ff19e029SMenno Lageman } 1116ff19e029SMenno Lageman while (task_commit_head != NULL) { 1117ff19e029SMenno Lageman task_t *tk; 1118ff19e029SMenno Lageman 1119ff19e029SMenno Lageman tk = task_commit_head; 1120ff19e029SMenno Lageman task_commit_head = task_commit_head->tk_commit_next; 1121ff19e029SMenno Lageman if (task_commit_head == NULL) 1122ff19e029SMenno Lageman task_commit_tail = NULL; 1123ff19e029SMenno Lageman mutex_exit(&task_commit_lock); 1124ff19e029SMenno Lageman exacct_commit_task(tk); 1125ff19e029SMenno Lageman mutex_enter(&task_commit_lock); 1126ff19e029SMenno Lageman } 1127ff19e029SMenno Lageman } 1128ff19e029SMenno Lageman } 1129