From owner-freebsd-arch Sun Nov 26 12:18:36 2000 Delivered-To: freebsd-arch@freebsd.org Received: from mail.interware.hu (mail.interware.hu [195.70.32.130]) by hub.freebsd.org (Postfix) with ESMTP id 8491537B479; Sun, 26 Nov 2000 12:18:28 -0800 (PST) Received: from dakar-60.budapest.interware.hu ([195.70.51.124] helo=elischer.org) by mail.interware.hu with esmtp (Exim 3.16 #1 (Debian)) id 1408Fj-0002ze-00; Sun, 26 Nov 2000 21:18:24 +0100 Message-ID: <3A216FFE.BE0F780F@elischer.org> Date: Sun, 26 Nov 2000 12:18:06 -0800 From: Julian Elischer X-Mailer: Mozilla 4.7 [en] (X11; U; FreeBSD 5.0-CURRENT i386) X-Accept-Language: en, hu MIME-Version: 1.0 To: arch@FreeBSD.ORG, jasone@freebsd.org Subject: Re: Threads .. chopping up 'struct proc' References: <3A1B0B64.6D694248@elischer.org> <3A211C82.2464D07E@elischer.org> Content-Type: text/plain; charset=iso-8859-15 Content-Transfer-Encoding: 7bit Sender: owner-freebsd-arch@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG I'v been looking a the proc srtucture.. The aim is to eventually move some of the fields into a struct KSE (struct schedbox?) struct KSEC (struct threadcontext?) struct KSEG (struct schedgroup?) Initially we would simply include one of each of these in the struct proc, but link them together as if they were correctly connected up. we would use macros such as: #define p_estcpu p_kse.kse_estcpu to keep present code working.... eventually functions that get changed to receive a kse directly would just use kse->kse_estcpu and if they need proc they can use kse->kse_proc. But until then, we'd start by simply separating the fields and using macros. Then we can convert calls at our leasure. However when going through the fields in struct proc, some difficulties become obvious. Here's my initial division of the fields. I've added a comment at the beginning of each line that indicates where I think it should go, however I'm not convinced about some of them: P = stays in struct proc E = goes to 'KSE' struct (schedulable entity) G = goes to 'group' struct C = goes to 'sleepable Context' struct. I note with [XXX] things I am sure about, or do nut really understand. these are usually new fields to do with things like events, or fields where the semantics of the feature have not been decided for a threaded environment. E.g. WHO GETS A SIGNAL? struct proc { /*E*/ TAILQ_ENTRY(proc) p_procq; /* run/mutex queue. */ [this may need to be split to two entries.. one in a KSE or and one in a KSEG, depending on how we do things ] /*C*/ TAILQ_ENTRY(proc) p_slpq; /* sleep queue. */ /*P*/ LIST_ENTRY(proc) p_list; /* List of all processes. */ /* substructures: */ /*P*/ struct pcred *p_cred; /* Process owner's identity. */ /*P*/ struct filedesc *p_fd; /* Ptr to open files structure. */ /*P*/ struct pstats *p_stats; /* Accounting/statistics (PROC ONLY). */ [some of these may need to be duplicated in the KSE and KSEG.. maybe even Context] /*P*/ struct plimit *p_limit; /* Process limits. */ /*P*/ struct vm_object *p_upages_obj;/* Upages object */ /*P*/ struct procsig *p_procsig; [Well, actually who gets signals? maybe this is per KSE? per KSEG? maybe even per Context as each context has a different user stack and signals are delivered on the user stack.. (unless set otherwise)] #define p_sigacts p_procsig->ps_sigacts #define p_sigignore p_procsig->ps_sigignore #define p_sigcatch p_procsig->ps_sigcatch #define p_ucred p_cred->pc_ucred #define p_rlimit p_limit->pl_rlimit /*C*/ int p_flag; /* P_* flags. */ [these flags will probably need to be shared out amongst the structures] /*C*/ char p_stat; /* S* process status. */ [as will these] char p_pad1[3]; /*P*/ pid_t p_pid; /* Process identifier. */ /*P*/ LIST_ENTRY(proc) p_hash; /* Hash chain. */ /*P*/ LIST_ENTRY(proc) p_pglist; /* List of processes in pgrp. */ /*P*/ struct proc *p_pptr; /* Pointer to parent process. */ /*P*/ LIST_ENTRY(proc) p_sibling; /* List of sibling processes. */ /*P*/ LIST_HEAD(, proc) p_children; /* Pointer to list of children. */ /*P*/ struct callout_handle p_ithandle; /* * Callout handle for scheduling * p_realtimer. */ [So who gets the resulting signal? Can differnt KSEGs have different timers running? what about KSEs? (I vote for KSEGs)] /* The following fields are all zeroed upon creation in fork. */ #define p_startzero p_oppid /*P*/ pid_t p_oppid; /* Save parent pid during ptrace. XXX */ /*C*/ int p_dupfd; /* Sideways return value from fdopen. XXX */ [whatever THIS means.. it's a hack so C is the safest place for it] /*P*/ struct vmspace *p_vmspace; /* Address space. */ /* scheduling */ [I've shown the following as being in the KSE structure. they would be collected there, but the priority is worked out for the entire KSEG so it probably collects the data from all of the KSEs. UNLESS we decide that all KSEs can have independent priorities, in which case how do you control how their priorities relate..] /*E*/ u_int p_estcpu; /* Time averaged value of p_cpticks. */ /*E*/ int p_cpticks; /* Ticks of cpu time. */ /*E*/ fixpt_t p_pctcpu; /* %cpu for this process during p_swtime */ void *p_wchan; /* Sleep address. */ const char *p_wmesg; /* Reason for sleep. */ /*P*/ u_int p_swtime; /* Time swapped in or out. */ /*E?*/ u_int p_slptime; /* Time since last blocked. */ [what does this mean?] /*?*/ struct itimerval p_realtimer; /* Alarm timer. */ [who gets these? who can set them? what is their scope?] /*P*/ u_int64_t p_runtime; /* Real time in microsec. */ [If we treat separate KSEGs as seperate processes, do we keep the below fields per KSEG? */ /*G?*/ u_int64_t p_uu; /* Previous user time in microsec. */ /*G?*/ u_int64_t p_su; /* Previous system time in microsec. */ /*G?*/ u_int64_t p_iu; /* Previous interrupt time in usec. */ [how about these? do we agregate? or collect per KSE? Is there a separate statclock per CPU?] /*P?*/ u_int64_t p_uticks; /* Statclock hits in user mode. */ /*P?*/ u_int64_t p_sticks; /* Statclock hits in system mode. */ /*P?*/ u_int64_t p_iticks; /* Statclock hits processing intr. */ /*P*/ int p_traceflag; /* Kernel trace points. */ /*P*/ struct vnode *p_tracep; /* Trace to vnode. */ [do we trace all KSEs at once? how do we trace individual threads? */ /*P*/ sigset_t p_siglist; /* Signals arrived but not delivered. */ [who gets signals? does each KSEG (KSE?) have its own handler?] /*P*/ struct vnode *p_textvp; /* Vnode of executable. */ /*P*/ char p_lock; /* Process lock (prevent swap) count. */ /*E*/ u_char p_oncpu; /* Which cpu we are on */ /*E?*/ u_char p_lastcpu; /* Last cpu we were on */ [each context or each KSE? KSEs can't migrate, (under discussion)] /*EG?*/ char p_rqindex; /* Run queue index */ Who is on the run queue? KSE or KSEG? /*C*/ short p_locks; /* DEBUG: lockmgr count of held locks */ /*C*/ short p_simple_locks; /* DEBUG: count of held simple locks */ [If you cannot sleep or be interrupted with these they could be in the KSE] /*P?*/ unsigned int p_stops; /* procfs event bitmask */ /*P?*/ unsigned int p_stype; /* procfs stop event type */ /*P?*/ char p_step; /* procfs stop *once* flag */ /*P?*/ unsigned char p_pfsflags; /* procfs flags */ [the procfs stuff is problematical... dependign in what it does and what it is used for, the semantics might vary] char p_pad3[2]; /* padding for alignment */ /*C*/ register_t p_retval[2]; /* syscall aux returns */ /*P*/ struct sigiolst p_sigiolst; /* list of sigio sources */ [who gets signals?] /*P*/ int p_sigparent; /* signal to parent on exit */ /*P*/ sigset_t p_oldsigmask; /* saved mask from before sigpause */ [one per signal scope.. what IS the scope of a signal?] /*P*/ int p_sig; /* for core dump/debugger XXX */ /*P*/ u_long p_code; /* for core dump/debugger XXX */ /*P?*/ struct klist p_klist; /* knotes attached to this process */ /*C?*/ LIST_HEAD(, mtx) p_heldmtx; /* for debugging code */ /*CE?*/ struct mtx *p_blocked; /* Mutex process is blocked on */ [depending on what this means ] /*C*/ LIST_HEAD(, mtx) p_contested; /* contested locks */ /* End area that is zeroed on creation. */ #define p_endzero p_startcopy /* The following fields are all copied upon creation in fork. */ #define p_startcopy p_sigmask /*P?*/ sigset_t p_sigmask; /* Current signal mask. */ /*C?*/ stack_t p_sigstk; /* sp & on stack state variable */ [what is the scope of a signal?] /*??*/ int p_magic; /* Magic number. */ [The fields below would be in the KSEG if the priority of all KSEs in a KSEG were to be calculated at one time.] /*G*/ u_char p_priority; /* Process priority. */ /*G*/ u_char p_usrpri; /* User-priority based on p_cpu and p_nice. */ /*G*/ u_char p_nativepri; /* Priority before propogation. */ /*G*/ char p_nice; /* Process "nice" value. */ /*P*/ char p_comm[MAXCOMLEN+1]; /*P*/ struct pgrp *p_pgrp; /* Pointer to process group. */ /*P*/ struct sysentvec *p_sysent; /* System call dispatch information. */ /*G*/ struct rtprio p_rtprio; /* Realtime priority. */ [priorities ar eper KSEG] /*P*/ struct prison *p_prison; /*P*/ struct pargs *p_args; [Either the whole Process is in gaol or it isn't] /* End area that is copied on creation. */ #define p_endcopy p_addr /*P?*/ struct user *p_addr; /* Kernel virtual addr of u-area (PROC ONLY). */ [XXX Are there 'per KSE' filds there? (actually yes there are...the pcb is there). /*C?*/ struct mdproc p_md; /* Any machine-dependent fields. */ [there is a trapframe there. not sure what it;s used for] /*P*/ u_short p_xstat; /* Exit status for wait; also stop signal. */ /*P*/ u_short p_acflag; /* Accounting flags. */ [these may be collected per KSE and harvested when needed] /*P*/ struct rusage *p_ru; /* Exit information. XXX */ /*P*/ int p_nthreads; /* number of threads (only in leader) */ [not sure how this is used... may become redundant] /*G?*/ void *p_aioinfo; /* ASYNC I/O info */ [will aio be 'per KSE, per KSEG or per PROC?] /*C*/ int p_wakeup; /* thread id */ [will surely change] /*P*/ struct proc *p_peers; /*P*/ struct proc *p_leader; /*C*/ struct pasleep p_asleep; /* Used by asleep()/await(). */ /*P*/ void *p_emuldata; /* process-specific emulator state data */ /*C*/ struct ithd *p_ithd; /* for interrupt threads only */ }; Obviously before we can really finish this we need to decide, what the scope of signals is.. Who gets externally genrated signals? Who gets signals that are the result of an action (e.g. SIGIO, SIGPIPE)? WHich signals are diverted when you allocate a signal stack? In the same context, what is the scope of aio? where are the results delivered? who is responsible for the kernel threads that do the work? do we allocate a KSE to run them? etc.etc. What is the scope of the timers and such? All this makes a difference in where the fields live.... Does anyone have comments? (Everyone has been VERY quiet so far!!!) julian -- __--_|\ Julian Elischer / \ julian@elischer.org ( OZ ) World tour 2000 ---> X_.---._/ presently in: Budapest v To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-arch" in the body of the message