Files
Arquivotheca.AIX-4.1.3/bos/kernel/proc/newthread.c
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

305 lines
9.1 KiB
C

static char sccsid[] = "@(#)37 1.20 src/bos/kernel/proc/newthread.c, sysproc, bos41J, 9513A_all 3/24/95 15:30:34";
/*
* COMPONENT_NAME: SYSPROC
*
* FUNCTIONS: TCDT_SIZE
* alloc_tcdt
* freethread
* newthread
* thread_dump_init
* threadcdtf
*
* ORIGINS: 27, 3, 26, 83
*
*
* This module contains IBM CONFIDENTIAL code. -- (IBM
* Confidential Restricted when combined with the aggregated
* modules for this product)
* SOURCE MATERIALS
*
* (C) COPYRIGHT International Business Machines Corp. 1993, 1995
* All Rights Reserved
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
/*
* LEVEL 1, 5 Years Bull Confidential Information
*/
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/sched.h>
#include <sys/sleep.h>
#include <sys/var.h>
#include <sys/systm.h>
#include <sys/intr.h>
#include <sys/errno.h>
#include <sys/syspest.h>
#include <sys/dump.h>
#include <sys/malloc.h>
#include <sys/pseg.h>
#include <sys/user.h>
#include <sys/lock_alloc.h>
#include <sys/lockname.h>
extern ulong g_kxsrval; /* value of segment with thread table */
struct pm_heap thread_cb; /* thread tables control block */
static void *threadcdt; /* dump table for threads */
/* reserve dump table slots for thread table entry and kernel region */
#define TCDT_INCR 128 /* xmalloc cdt_entry's */
#define TCDT_SIZE(n) (sizeof(struct cdt_head) + (n*sizeof(struct cdt_entry)))
#define TCDT_INCREASE (TCDT_INCR * sizeof(struct cdt_entry))
#define TCDT_DECREASE (2 * TCDT_INCR * sizeof(struct cdt_entry))
/*
* NAME: newthread
*
* FUNCTION: allocate a new thread table entry
*
* NOTES:
*
* This creates a thread that eventually will be turned into
* either a user thread or a kernel thread.
*
* The TSIDL state is needed because the user needs to explicitly
* start the thread. Threads in the TSIDL state cannot be sent signals.
*
* Thread state transition :
* TSNONE ==> TSIDL
*
* [In fact, the state is not changed to TSIDL because it must be done
* atomically with the process state transition to SIDL and the linkage
* (t_procp & p_threadlist).]
*
* EXECUTION ENVIRONMENT:
* Must be called under a process.
* When called from strtdisp() during system initialization,
* there is no u-block available. That is why the address
* to return error codes is passed in place of u.u_error.
*
* RETURNS: thread struct of newly created thread, if successful;
* NULL, if unsuccessful (*error has the reason).
*
* Possible error values are:
* EAGAIN, if unable to create a new thread
* ENOMEM, if unable to pin more thread structures
*/
struct thread *
newthread(register char *error)
/* error address to return errno value */
{
register struct thread *t; /* new thread pointer */
register struct thread *ct = curthread; /* current thread */
if (!(t = (struct thread *)pm_alloc(&thread_cb, error)))
return(NULL);
/* Minimize cache misses by initializing in order */
t->t_suspend = 1; /* kernel mode: prevent sig */
t->t_flags = ct->t_flags & TKTHREAD;
t->t_stackp = ct->t_stackp;
t->t_uthreadp = &uthr0; /* fixed address (default) */
t->t_userp = &U; /* fixed address */
t->t_synch = (struct thread *)EVENT_NULL; /* null value for sync */
t->t_tsleep = EVENT_NULL;
t->t_userdata = ct->t_userdata;
#ifdef _POWER_MP
t->t_cpuid = t->t_scpuid = ct->t_scpuid;
t->t_affinity = ct->t_affinity;
#endif
t->t_pri = ct->t_pri;
t->t_policy = ct->t_policy;
t->t_wakepri = PIDLE; /* null value for wakepri */
t->t_sav_pri = ct->t_sav_pri;
t->t_sigmask = ct->t_sigmask;
/* t_tid is allocated by pm_alloc */
return(t);
}
/*
* NAME: freethread
*
* FUNCTION: return a thread slot to the free list.
*
* NOTE:
* This is the inverse operation of newthread().
*
* Thread state transition :
* xxx ==> TSNONE
*
* EXECUTION ENVIRONMENT:
* Must own proc_tbl_lock.
*/
void
freethread(struct thread *t /* thread table entry to free */ )
{
ASSERT((t->t_state == TSNONE) || lock_mine(&proc_tbl_lock));
/* mark slot available */
t->t_state = TSNONE;
/* return thread structure to the free list */
pm_free(&thread_cb, (char *)t);
}
/*
* NAME: alloc_tcdt
*
* FUNCTION: allocate memory for threadcdt, thread component dump table
*
* NOTES:
* The threadcdt must be pinned in memory so that
* when a dump is done, the table can be filled in with
* pointers to thread table slots and kernel regions. Therefore,
* 1(2) slot(s) in the dump table are needed for each process.
* [kernel stack and uthread should be dumped with thread instead of
* process]
*
* EXECUTION ENVIRONMENT:
* Calls xmalloc. A realloc to extend or shrink requested memory
* would be better.
*
* RETURNS: None.
*
*/
void
alloc_tcdt( int nthread )
{
register int size; /* size of memory to allocate */
register struct cdt_head *ch; /* component dump table header ptr */
register void *new_tcdt; /* new thread component dump table */
register void *x;
size = TCDT_SIZE( nthread );
ch = (struct cdt_head *) threadcdt;
/* increase tcdt size by TCDT_INCREASE or decrease by TCDT_DECREASE */
if (!ch || size >= ch->_cdt_len)
size += TCDT_INCREASE;
else if (size > (ch->_cdt_len - TCDT_DECREASE))
return;
/* allocate pinned memory for thread component dump table */
if ((new_tcdt = (void *)
xmalloc((uint) size, (uint) 0, pinned_heap)) != NULL)
{
bzero(new_tcdt, size);
x = threadcdt; /* save old table */
threadcdt = new_tcdt; /* set new table */
if (x)
xmfree(x, pinned_heap); /* free old table */
ch = (struct cdt_head *) threadcdt;
strcpy(ch->_cdt_name,"thrd"); /* component is thread */
ch->_cdt_len = size; /* tcdt length */
ch->_cdt_magic = DMP_MAGIC; /* dump magic number */
}
}
/*
* NAME: threadcdtf
*
* FUNCTION: thread component dump table function initializes threadcdt
* with pointers to threads' thread table slots and to their
* kernel region ()
*
* RETURNS: Called by dmp_do at dump time, threadcdtf returns
* a pointer to threadcdt, the thread component dump table.
*/
static struct cdt_head *
threadcdtf( int status )
{
register struct thread *t;
register struct uthread *ut;
register struct cdt_entry *c, *ce;
struct cdt_head *ch;
if (status == 2 || threadcdt == NULL)
return( (struct cdt_head *) NULL);
ch = (struct cdt_head *) threadcdt;
c = (struct cdt_entry *) (ch + 1);
ce = (struct cdt_entry *) ((char *) ch + ch->_cdt_len);
/* dump thread data */
for (t = thread; c < ce && t < (struct thread *)v.ve_thread; t++) {
if (t->t_state == TSNONE)
continue;
/* dump thread entry */
sprintf(c->d_name, "%dt",t - thread); /* name is "slot#t" */
c->d_len = sizeof(struct thread);
c->d_ptr = (char *) t;
c->d_segval = g_kxsrval;
c++;
/* dump user thread structure */
sprintf(c->d_name, "%du",t - thread); /* "slot#u" */
c->d_len = sizeof(struct uthread);
c->d_ptr = (char *) t->t_uthreadp;
c->d_segval = t->t_procp->p_adspace;
c++;
/*
* Only dump the kernel stack if we're in kernel mode,
* since a program cannot crash the system in user mode.
* Note: there is a small window where the thread is
* still SZOMB but has already lost its process private
* segment and thus has no stack anymore.
*/
if (t->t_suspend && t->t_procp->p_adspace != NULLSEGVAL) {
sprintf(c->d_name, "%ds",t - thread); /* "slot#s" */
/*
* Calculate kernel stack size.
* normal stack.
* special fork stack.
* stack has been moved - grab a page.
*/
ut = (struct uthread *)
vm_att(t->t_procp->p_adspace, t->t_uthreadp);
c->d_ptr = (char *)(ut->ut_save.gpr[1] & ~(PAGESIZE-1));
c->d_len = (ulong)ut->ut_kstack - (ulong)c->d_ptr;
if ((c->d_len < 0) || (c->d_len > KSTACKSIZE))
c->d_len = (ulong)&__ublock - KSTACKSIZE -
(ulong)c->d_ptr;
if ((c->d_len < 0) || (c->d_len > KSTACKSIZE))
c->d_len = PAGESIZE;
c->d_segval = as_getsrval(&ut->ut_save.as, c->d_ptr);
vm_det(ut);
c++;
}
}
ch->_cdt_len = (char *) c - (char *) ch; /* actual length of tcdt */
return( (struct cdt_head *) ch );
}
/*
* NAME: thread_dump_init
*
* FUNCTION: add thread component dump table to components to be dumped
*
* ENVIRONMENT: called once by strtdisp().
*
* RETURNS: none
*
*/
void
thread_dump_init()
{
dmp_add(threadcdtf); /* put thread component in dump device table */
}