darwin-xnu/bsd/kern/kern_fork.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2004 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/* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
  23/*
  24 * Copyright (c) 1982, 1986, 1989, 1991, 1993
  25 *      The Regents of the University of California.  All rights reserved.
  26 * (c) UNIX System Laboratories, Inc.
  27 * All or some portions of this file are derived from material licensed
  28 * to the University of California by American Telephone and Telegraph
  29 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
  30 * the permission of UNIX System Laboratories, Inc.
  31 *
  32 * Redistribution and use in source and binary forms, with or without
  33 * modification, are permitted provided that the following conditions
  34 * are met:
  35 * 1. Redistributions of source code must retain the above copyright
  36 *    notice, this list of conditions and the following disclaimer.
  37 * 2. Redistributions in binary form must reproduce the above copyright
  38 *    notice, this list of conditions and the following disclaimer in the
  39 *    documentation and/or other materials provided with the distribution.
  40 * 3. All advertising materials mentioning features or use of this software
  41 *    must display the following acknowledgement:
  42 *      This product includes software developed by the University of
  43 *      California, Berkeley and its contributors.
  44 * 4. Neither the name of the University nor the names of its contributors
  45 *    may be used to endorse or promote products derived from this software
  46 *    without specific prior written permission.
  47 *
  48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  51 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  58 * SUCH DAMAGE.
  59 *
  60 *      @(#)kern_fork.c 8.8 (Berkeley) 2/14/95
  61 */
  62
  63#include <kern/assert.h>
  64#include <sys/param.h>
  65#include <sys/systm.h>
  66#include <sys/filedesc.h>
  67#include <sys/kernel.h>
  68#include <sys/malloc.h>
  69#include <sys/proc_internal.h>
  70#include <sys/kauth.h>
  71#include <sys/user.h>
  72#include <sys/resourcevar.h>
  73#include <sys/vnode_internal.h>
  74#include <sys/file_internal.h>
  75#include <sys/acct.h>
  76#if KTRACE
  77#include <sys/ktrace.h>
  78#endif
  79
  80#include <bsm/audit_kernel.h>
  81
  82#include <mach/mach_types.h>
  83#include <kern/kern_types.h>
  84#include <kern/kalloc.h>
  85#include <kern/mach_param.h>
  86#include <kern/task.h>
  87#include <kern/zalloc.h>
  88
  89#include <machine/spl.h>
  90
  91#include <vm/vm_protos.h>       // for vm_map_commpage64
  92
  93thread_t cloneproc(struct proc *, int); 
  94struct proc * forkproc(struct proc *, int);
  95thread_t procdup(struct proc *child, struct proc *parent);
  96
  97#define DOFORK  0x1     /* fork() system call */
  98#define DOVFORK 0x2     /* vfork() system call */
  99static int fork1(struct proc *, long, register_t *);
 100
 101/*
 102 * fork system call.
 103 */
 104int
 105fork(struct proc *p, __unused void *uap, register_t *retval)
 106{
 107        return (fork1(p, (long)DOFORK, retval));
 108}
 109
 110/*
 111 * vfork system call
 112 */
 113int
 114vfork(struct proc *p, void *uap, register_t *retval)
 115{
 116        register struct proc * newproc;
 117        register uid_t uid;
 118        thread_t cur_act = (thread_t)current_thread();
 119        int count;
 120        task_t t;
 121        uthread_t ut;
 122
 123        /*
 124         * Although process entries are dynamically created, we still keep
 125         * a global limit on the maximum number we will create.  Don't allow
 126         * a nonprivileged user to use the last process; don't let root
 127         * exceed the limit. The variable nprocs is the current number of
 128         * processes, maxproc is the limit.
 129         */
 130        uid = kauth_cred_get()->cr_ruid;
 131        if ((nprocs >= maxproc - 1 && uid != 0) || nprocs >= maxproc) {
 132                tablefull("proc");
 133                retval[1] = 0;
 134                return (EAGAIN);
 135        }
 136
 137        /*
 138         * Increment the count of procs running with this uid. Don't allow
 139         * a nonprivileged user to exceed their current limit.
 140         */
 141        count = chgproccnt(uid, 1);
 142        if (uid != 0 && count > p->p_rlimit[RLIMIT_NPROC].rlim_cur) {
 143                (void)chgproccnt(uid, -1);
 144                return (EAGAIN);
 145        }
 146
 147        ut = (struct uthread *)get_bsdthread_info(cur_act);
 148        if (ut->uu_flag & UT_VFORK) {
 149                printf("vfork called recursively by %s\n", p->p_comm);
 150                (void)chgproccnt(uid, -1);
 151                return (EINVAL);
 152        }
 153        p->p_flag  |= P_VFORK;
 154        p->p_vforkcnt++;
 155
 156        /* The newly created process comes with signal lock held */
 157        newproc = (struct proc *)forkproc(p,1);
 158
 159        AUDIT_ARG(pid, newproc->p_pid);
 160
 161        LIST_INSERT_AFTER(p, newproc, p_pglist);
 162        newproc->p_pptr = p;
 163        newproc->task = p->task;
 164        LIST_INSERT_HEAD(&p->p_children, newproc, p_sibling);
 165        LIST_INIT(&newproc->p_children);
 166        LIST_INSERT_HEAD(&allproc, newproc, p_list);
 167        LIST_INSERT_HEAD(PIDHASH(newproc->p_pid), newproc, p_hash);
 168        TAILQ_INIT(& newproc->p_evlist);
 169        newproc->p_stat = SRUN;
 170        newproc->p_flag  |= P_INVFORK;
 171        newproc->p_vforkact = cur_act;
 172
 173        ut->uu_flag |= UT_VFORK;
 174        ut->uu_proc = newproc;
 175        ut->uu_userstate = (void *)act_thread_csave();
 176        ut->uu_vforkmask = ut->uu_sigmask;
 177
 178        /* temporarily drop thread-set-id state */
 179        if (ut->uu_flag & UT_SETUID) {
 180                ut->uu_flag |= UT_WASSETUID;
 181                ut->uu_flag &= ~UT_SETUID;
 182        }
 183        
 184        thread_set_child(cur_act, newproc->p_pid);
 185
 186        microtime(&newproc->p_stats->p_start);
 187        newproc->p_acflag = AFORK;
 188
 189        /*
 190         * Preserve synchronization semantics of vfork.  If waiting for
 191         * child to exec or exit, set P_PPWAIT on child, and sleep on our
 192         * proc (in case of exit).
 193         */
 194        newproc->p_flag |= P_PPWAIT;
 195
 196        /* drop the signal lock on the child */
 197        signal_unlock(newproc);
 198
 199        retval[0] = newproc->p_pid;
 200        retval[1] = 1;                  /* mark child */
 201
 202        return (0);
 203}
 204
 205/*
 206 * Return to parent vfork ehread()
 207 */
 208void
 209vfork_return(__unused thread_t th_act, struct proc *p, struct proc *p2,
 210        register_t *retval)
 211{
 212        thread_t cur_act = (thread_t)current_thread();
 213        uthread_t ut;
 214        
 215        ut = (struct uthread *)get_bsdthread_info(cur_act);
 216
 217        act_thread_catt(ut->uu_userstate);
 218
 219        /* Make sure only one at this time */
 220        p->p_vforkcnt--;
 221        if (p->p_vforkcnt <0)
 222                panic("vfork cnt is -ve");
 223        if (p->p_vforkcnt <=0)
 224                p->p_flag  &= ~P_VFORK;
 225        ut->uu_userstate = 0;
 226        ut->uu_flag &= ~UT_VFORK;
 227        /* restore thread-set-id state */
 228        if (ut->uu_flag & UT_WASSETUID) {
 229                ut->uu_flag |= UT_SETUID;
 230                ut->uu_flag &= UT_WASSETUID;
 231        }
 232        ut->uu_proc = 0;
 233        ut->uu_sigmask = ut->uu_vforkmask;
 234        p2->p_flag  &= ~P_INVFORK;
 235        p2->p_vforkact = (void *)0;
 236
 237        thread_set_parent(cur_act, p2->p_pid);
 238
 239        if (retval) {
 240                retval[0] = p2->p_pid;
 241                retval[1] = 0;                  /* mark parent */
 242        }
 243
 244        return;
 245}
 246
 247thread_t
 248procdup(struct proc *child, struct proc *parent)
 249{
 250        thread_t                thread;
 251        task_t                  task;
 252        kern_return_t   result;
 253
 254        if (parent->task == kernel_task)
 255                result = task_create_internal(TASK_NULL, FALSE, &task);
 256        else
 257                result = task_create_internal(parent->task, TRUE, &task);
 258        if (result != KERN_SUCCESS)
 259            printf("fork/procdup: task_create failed. Code: 0x%x\n", result);
 260        child->task = task;
 261        /* task->proc = child; */
 262        set_bsdtask_info(task, child);
 263        if (parent->p_flag & P_LP64) {
 264                task_set_64bit(task, TRUE);
 265                child->p_flag |= P_LP64;
 266#ifdef __PPC__
 267                /* LP64todo - clean up this hacked mapping of commpage */
 268                pmap_map_sharedpage(task, get_map_pmap(get_task_map(task)));
 269                vm_map_commpage64(get_task_map(task));
 270#endif  /* __PPC__ */
 271        } else {
 272                task_set_64bit(task, FALSE);
 273                child->p_flag &= ~P_LP64;
 274        }
 275        if (child->p_nice != 0)
 276                resetpriority(child);
 277                
 278        result = thread_create(task, &thread);
 279        if (result != KERN_SUCCESS)
 280            printf("fork/procdup: thread_create failed. Code: 0x%x\n", result);
 281
 282        return(thread);
 283}
 284
 285
 286static int
 287fork1(p1, flags, retval)
 288        struct proc *p1;
 289        long flags;
 290        register_t *retval;
 291{
 292        register struct proc *p2;
 293        register uid_t uid;
 294        thread_t newth;
 295        int count;
 296        task_t t;
 297
 298        /*
 299         * Although process entries are dynamically created, we still keep
 300         * a global limit on the maximum number we will create.  Don't allow
 301         * a nonprivileged user to use the last process; don't let root
 302         * exceed the limit. The variable nprocs is the current number of
 303         * processes, maxproc is the limit.
 304         */
 305        uid = kauth_cred_get()->cr_ruid;
 306        if ((nprocs >= maxproc - 1 && uid != 0) || nprocs >= maxproc) {
 307                tablefull("proc");
 308                retval[1] = 0;
 309                return (EAGAIN);
 310        }
 311
 312        /*
 313         * Increment the count of procs running with this uid. Don't allow
 314         * a nonprivileged user to exceed their current limit.
 315         */
 316        count = chgproccnt(uid, 1);
 317        if (uid != 0 && count > p1->p_rlimit[RLIMIT_NPROC].rlim_cur) {
 318                (void)chgproccnt(uid, -1);
 319                return (EAGAIN);
 320        }
 321
 322        /* The newly created process comes with signal lock held */
 323        newth = cloneproc(p1, 1);
 324        thread_dup(newth);
 325        /* p2 = newth->task->proc; */
 326        p2 = (struct proc *)(get_bsdtask_info(get_threadtask(newth)));
 327        set_security_token(p2);         /* propagate change of PID */
 328
 329        AUDIT_ARG(pid, p2->p_pid);
 330
 331        thread_set_child(newth, p2->p_pid);
 332
 333        microtime(&p2->p_stats->p_start);
 334        p2->p_acflag = AFORK;
 335
 336        /*
 337         * Preserve synchronization semantics of vfork.  If waiting for
 338         * child to exec or exit, set P_PPWAIT on child, and sleep on our
 339         * proc (in case of exit).
 340         */
 341        if (flags == DOVFORK)
 342                p2->p_flag |= P_PPWAIT;
 343        /* drop the signal lock on the child */
 344        signal_unlock(p2);
 345
 346        (void) thread_resume(newth);
 347
 348        /* drop the extra references we got during the creation */
 349        if ((t = (task_t)get_threadtask(newth)) != NULL) {
 350                task_deallocate(t);
 351        }
 352        thread_deallocate(newth);
 353
 354        KNOTE(&p1->p_klist, NOTE_FORK | p2->p_pid);
 355
 356        while (p2->p_flag & P_PPWAIT)
 357                tsleep(p1, PWAIT, "ppwait", 0);
 358
 359        retval[0] = p2->p_pid;
 360        retval[1] = 0;                  /* mark parent */
 361
 362        return (0);
 363}
 364
 365/*
 366 * cloneproc()
 367 *
 368 * Create a new process from a specified process.
 369 * On return newly created child process has signal
 370 * lock held to block delivery of signal to it if called with
 371 * lock set. fork() code needs to explicity remove this lock 
 372 * before signals can be delivered
 373 */
 374thread_t
 375cloneproc(p1, lock)
 376        register struct proc *p1;
 377        register int lock;
 378{
 379        register struct proc *p2;
 380        thread_t th;
 381
 382        p2 = (struct proc *)forkproc(p1,lock);
 383
 384
 385        th = procdup(p2, p1);   /* child, parent */
 386
 387        LIST_INSERT_AFTER(p1, p2, p_pglist);
 388        p2->p_pptr = p1;
 389        LIST_INSERT_HEAD(&p1->p_children, p2, p_sibling);
 390        LIST_INIT(&p2->p_children);
 391        LIST_INSERT_HEAD(&allproc, p2, p_list);
 392        LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash);
 393        TAILQ_INIT(&p2->p_evlist);
 394        /*
 395         * Make child runnable, set start time.
 396         */
 397        p2->p_stat = SRUN;
 398
 399        return(th);
 400}
 401
 402struct proc *
 403forkproc(p1, lock)
 404        register struct proc *p1;
 405        register int lock;
 406{
 407        register struct proc *p2, *newproc;
 408        static int nextpid = 0, pidchecked = 0;
 409
 410        /* Allocate new proc. */
 411        MALLOC_ZONE(newproc, struct proc *,
 412                        sizeof *newproc, M_PROC, M_WAITOK);
 413        if (newproc == NULL)
 414                panic("forkproc: M_PROC zone exhausted");
 415        MALLOC_ZONE(newproc->p_stats, struct pstats *,
 416                        sizeof *newproc->p_stats, M_SUBPROC, M_WAITOK);
 417        if (newproc->p_stats == NULL)
 418                panic("forkproc: M_SUBPROC zone exhausted (p_stats)");
 419        MALLOC_ZONE(newproc->p_sigacts, struct sigacts *,
 420                        sizeof *newproc->p_sigacts, M_SUBPROC, M_WAITOK);
 421        if (newproc->p_sigacts == NULL)
 422                panic("forkproc: M_SUBPROC zone exhausted (p_sigacts)");
 423
 424        /*
 425         * Find an unused process ID.  We remember a range of unused IDs
 426         * ready to use (from nextpid+1 through pidchecked-1).
 427         */
 428        nextpid++;
 429retry:
 430        /*
 431         * If the process ID prototype has wrapped around,
 432         * restart somewhat above 0, as the low-numbered procs
 433         * tend to include daemons that don't exit.
 434         */
 435        if (nextpid >= PID_MAX) {
 436                nextpid = 100;
 437                pidchecked = 0;
 438        }
 439        if (nextpid >= pidchecked) {
 440                int doingzomb = 0;
 441
 442                pidchecked = PID_MAX;
 443                /*
 444                 * Scan the active and zombie procs to check whether this pid
 445                 * is in use.  Remember the lowest pid that's greater
 446                 * than nextpid, so we can avoid checking for a while.
 447                 */
 448                p2 = allproc.lh_first;
 449again:
 450                for (; p2 != 0; p2 = p2->p_list.le_next) {
 451                        while (p2->p_pid == nextpid ||
 452                            p2->p_pgrp->pg_id == nextpid ||
 453                                p2->p_session->s_sid == nextpid) {
 454                                nextpid++;
 455                                if (nextpid >= pidchecked)
 456                                        goto retry;
 457                        }
 458                        if (p2->p_pid > nextpid && pidchecked > p2->p_pid)
 459                                pidchecked = p2->p_pid;
 460                        if (p2->p_pgrp && p2->p_pgrp->pg_id > nextpid && 
 461                            pidchecked > p2->p_pgrp->pg_id)
 462                                pidchecked = p2->p_pgrp->pg_id;
 463                        if (p2->p_session->s_sid > nextpid &&
 464                                pidchecked > p2->p_session->s_sid)
 465                                pidchecked = p2->p_session->s_sid;
 466                }
 467                if (!doingzomb) {
 468                        doingzomb = 1;
 469                        p2 = zombproc.lh_first;
 470                        goto again;
 471                }
 472        }
 473
 474        nprocs++;
 475        p2 = newproc;
 476        p2->p_stat = SIDL;
 477        p2->p_shutdownstate = 0;
 478        p2->p_pid = nextpid;
 479
 480        /*
 481         * Make a proc table entry for the new process.
 482         * Start by zeroing the section of proc that is zero-initialized,
 483         * then copy the section that is copied directly from the parent.
 484         */
 485        bzero(&p2->p_startzero,
 486            (unsigned) ((caddr_t)&p2->p_endzero - (caddr_t)&p2->p_startzero));
 487        bcopy(&p1->p_startcopy, &p2->p_startcopy,
 488            (unsigned) ((caddr_t)&p2->p_endcopy - (caddr_t)&p2->p_startcopy));
 489        p2->vm_shm = (void *)NULL; /* Make sure it is zero */
 490
 491        /*
 492         * Some flags are inherited from the parent.
 493         * Duplicate sub-structures as needed.
 494         * Increase reference counts on shared objects.
 495         * The p_stats and p_sigacts substructs are set in vm_fork.
 496         */
 497        p2->p_flag = (p1->p_flag & (P_LP64 | P_CLASSIC | P_AFFINITY));
 498        if (p1->p_flag & P_PROFIL)
 499                startprofclock(p2);
 500        /*
 501         * Note that if the current thread has an assumed identity, this
 502         * credential will be granted to the new process.
 503         */
 504        p2->p_ucred = kauth_cred_get_with_ref();
 505
 506        lck_mtx_init(&p2->p_mlock, proc_lck_grp, proc_lck_attr);
 507        lck_mtx_init(&p2->p_fdmlock, proc_lck_grp, proc_lck_attr);
 508        klist_init(&p2->p_klist);
 509
 510        /* bump references to the text vnode */
 511        p2->p_textvp = p1->p_textvp;
 512        if (p2->p_textvp) {
 513                vnode_rele(p2->p_textvp);
 514        }
 515        /* XXX may fail to copy descriptors to child */
 516        p2->p_fd = fdcopy(p1);
 517
 518        if (p1->vm_shm) {
 519                /* XXX may fail to attach shm to child */
 520                (void)shmfork(p1,p2);
 521        }
 522        /*
 523         * If p_limit is still copy-on-write, bump refcnt,
 524         * otherwise get a copy that won't be modified.
 525         * (If PL_SHAREMOD is clear, the structure is shared
 526         * copy-on-write.)
 527         */
 528        if (p1->p_limit->p_lflags & PL_SHAREMOD)
 529                p2->p_limit = limcopy(p1->p_limit);
 530        else {
 531                p2->p_limit = p1->p_limit;
 532                p2->p_limit->p_refcnt++;
 533        }
 534
 535        bzero(&p2->p_stats->pstat_startzero,
 536            (unsigned) ((caddr_t)&p2->p_stats->pstat_endzero -
 537            (caddr_t)&p2->p_stats->pstat_startzero));
 538        bcopy(&p1->p_stats->pstat_startcopy, &p2->p_stats->pstat_startcopy,
 539            ((caddr_t)&p2->p_stats->pstat_endcopy -
 540             (caddr_t)&p2->p_stats->pstat_startcopy));
 541
 542        bzero(&p2->p_stats->user_p_prof, sizeof(struct user_uprof));
 543
 544        if (p1->p_sigacts != NULL)
 545                (void)memcpy(p2->p_sigacts,
 546                                p1->p_sigacts, sizeof *p2->p_sigacts);
 547        else
 548                (void)memset(p2->p_sigacts, 0, sizeof *p2->p_sigacts);
 549
 550        if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT)
 551                p2->p_flag |= P_CONTROLT;
 552
 553        p2->p_argslen = p1->p_argslen;
 554        p2->p_argc = p1->p_argc;
 555        p2->p_xstat = 0;
 556        p2->p_ru = NULL;
 557
 558        p2->p_debugger = 0;     /* don't inherit */
 559        lockinit(&p2->signal_lock, PVM, "signal", 0, 0);
 560        /* block all signals to reach the process */
 561        if (lock)
 562                signal_lock(p2);
 563        p2->sigwait = FALSE;
 564        p2->sigwait_thread = NULL;
 565        p2->exit_thread = NULL;
 566        p2->user_stack = p1->user_stack;
 567        p2->p_vforkcnt = 0;
 568        p2->p_vforkact = 0;
 569        p2->p_lflag  = 0;
 570        p2->p_ladvflag  = 0;
 571        p2->p_internalref  = 0;
 572        TAILQ_INIT(&p2->p_uthlist);
 573        TAILQ_INIT(&p2->aio_activeq);
 574        TAILQ_INIT(&p2->aio_doneq);
 575        p2->aio_active_count = 0;
 576        p2->aio_done_count = 0;
 577
 578#if KTRACE
 579        /*
 580         * Copy traceflag and tracefile if enabled.
 581         * If not inherited, these were zeroed above.
 582         */
 583        if (p1->p_traceflag&KTRFAC_INHERIT) {
 584                p2->p_traceflag = p1->p_traceflag;
 585                if ((p2->p_tracep = p1->p_tracep) != NULL) {
 586                        vnode_ref(p2->p_tracep);
 587                }
 588        }
 589#endif
 590        return(p2);
 591
 592}
 593
 594void
 595proc_lock(proc_t p)
 596{
 597        lck_mtx_lock(&p->p_mlock);
 598}
 599
 600void
 601proc_unlock(proc_t p)
 602{
 603        lck_mtx_unlock(&p->p_mlock);
 604}
 605
 606#include <kern/zalloc.h>
 607
 608struct zone     *uthread_zone;
 609int uthread_zone_inited = 0;
 610
 611void
 612uthread_zone_init(void)
 613{
 614        if (!uthread_zone_inited) {
 615                uthread_zone = zinit(sizeof(struct uthread),
 616                                        THREAD_MAX * sizeof(struct uthread),
 617                                        THREAD_CHUNK * sizeof(struct uthread),
 618                                        "uthreads");
 619                uthread_zone_inited = 1;
 620        }
 621}
 622
 623void *
 624uthread_alloc(task_t task, thread_t thr_act )
 625{
 626        struct proc *p;
 627        struct uthread *uth, *uth_parent;
 628        void *ut;
 629        boolean_t funnel_state;
 630
 631        if (!uthread_zone_inited)
 632                uthread_zone_init();
 633
 634        ut = (void *)zalloc(uthread_zone);
 635        bzero(ut, sizeof(struct uthread));
 636
 637        p = (struct proc *) get_bsdtask_info(task);
 638        uth = (struct uthread *)ut;
 639
 640        /*
 641         * Thread inherits credential from the creating thread, if both
 642         * are in the same task.
 643         *
 644         * If the creating thread has no credential or is from another
 645         * task we can leave the new thread credential NULL.  If it needs
 646         * one later, it will be lazily assigned from the task's process.
 647         */
 648        uth_parent = (struct uthread *)get_bsdthread_info(current_thread());
 649        if ((task == current_task()) && 
 650            (uth_parent != NULL) &&
 651            (uth_parent->uu_ucred != NOCRED)) {
 652                uth->uu_ucred = uth_parent->uu_ucred;
 653                kauth_cred_ref(uth->uu_ucred);
 654                /* the credential we just inherited is an assumed credential */
 655                if (uth_parent->uu_flag & UT_SETUID)
 656                        uth->uu_flag |= UT_SETUID;
 657        } else {
 658                uth->uu_ucred = NOCRED;
 659        }
 660        
 661        if (task != kernel_task) {
 662                
 663                funnel_state = thread_funnel_set(kernel_flock, TRUE);
 664                if (uth_parent) {
 665                        if (uth_parent->uu_flag & UT_SAS_OLDMASK)
 666                                uth->uu_sigmask = uth_parent->uu_oldmask;
 667                        else
 668                                uth->uu_sigmask = uth_parent->uu_sigmask;
 669                }
 670                uth->uu_act = thr_act;
 671                //signal_lock(p);
 672                if (p) {
 673                        TAILQ_INSERT_TAIL(&p->p_uthlist, uth, uu_list);
 674                }
 675                //signal_unlock(p);
 676                (void)thread_funnel_set(kernel_flock, funnel_state);
 677        }
 678
 679        return (ut);
 680}
 681
 682
 683void
 684uthread_free(task_t task, void *uthread, void * bsd_info)
 685{
 686        struct _select *sel;
 687        struct uthread *uth = (struct uthread *)uthread;
 688        struct proc * p = (struct proc *)bsd_info;
 689        boolean_t funnel_state;
 690
 691        /*
 692         * Per-thread audit state should never last beyond system
 693         * call return.  Since we don't audit the thread creation/
 694         * removal, the thread state pointer should never be
 695         * non-NULL when we get here.
 696         */
 697        assert(uth->uu_ar == NULL);
 698
 699        sel = &uth->uu_select;
 700        /* cleanup the select bit space */
 701        if (sel->nbytes) {
 702                FREE(sel->ibits, M_TEMP);
 703                FREE(sel->obits, M_TEMP);
 704        }
 705
 706        if (sel->allocsize && sel->wqset){
 707                kfree(sel->wqset, sel->allocsize);
 708                sel->count = 0;
 709                sel->allocsize = 0;
 710                sel->wqset = 0;
 711                sel->wql = 0;
 712        }
 713
 714        if (uth->uu_ucred != NOCRED)
 715                kauth_cred_rele(uth->uu_ucred);
 716
 717        if ((task != kernel_task) && p) {
 718                funnel_state = thread_funnel_set(kernel_flock, TRUE);
 719                //signal_lock(p);
 720                TAILQ_REMOVE(&p->p_uthlist, uth, uu_list);
 721                //signal_unlock(p);
 722                (void)thread_funnel_set(kernel_flock, funnel_state);
 723        }
 724        /* and free the uthread itself */
 725        zfree(uthread_zone, uthread);
 726}
 727
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.