Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 03 May 2015 21:04:03 +0800
From:      Julian Elischer <julian@freebsd.org>
To:        Mateusz Guzik <mjguzik@gmail.com>, Bruce Evans <brde@optusnet.com.au>
Cc:        freebsd-arch@freebsd.org
Subject:   Re: [PATCH 1/2] Generalised support for copy-on-write structures shared by threads.
Message-ID:  <55461CC3.2020306@freebsd.org>
In-Reply-To: <20150501165633.GA7112@dft-labs.eu>
References:  <1430188443-19413-1-git-send-email-mjguzik@gmail.com> <1430188443-19413-2-git-send-email-mjguzik@gmail.com> <20150428181802.F1119@besplex.bde.org> <20150501165633.GA7112@dft-labs.eu>

next in thread | previous in thread | raw e-mail | index | archive | help
On 5/2/15 12:56 AM, Mateusz Guzik wrote:
> On Tue, Apr 28, 2015 at 06:45:01PM +1000, Bruce Evans wrote:
>> On Tue, 28 Apr 2015, Mateusz Guzik wrote:
>>> diff --git a/sys/sys/proc.h b/sys/sys/proc.h
>>> index 64b99fc..f29d796 100644
>>> --- a/sys/sys/proc.h
>>> +++ b/sys/sys/proc.h
>>> @@ -225,6 +225,7 @@ struct thread {
>>> /* Cleared during fork1() */
>>> #define	td_startzero td_flags
>>> 	int		td_flags;	/* (t) TDF_* flags. */
>>> +	u_int		td_cowgeneration;/* (k) Generation of COW pointers. */
>>> 	int		td_inhibitors;	/* (t) Why can not run. */
>>> 	int		td_pflags;	/* (k) Private thread (TDP_*) flags. */
>>> 	int		td_dupfd;	/* (k) Ret value from fdopen. XXX */
>> This name is so verbose that it messes up the comment indentation.
>>
> Yeah, that's crap, but the naming is already inconsistent and verbose.
> For instance there is td_generation alrady.
>
> Is _cowgen variant ok?
td_cowgen is much preferable  with comment  "(k) generation of c.o.w. 
pointers."

>
>>> @@ -830,6 +832,11 @@ extern pid_t pid_max;
>>> 	KASSERT((p)->p_lock == 0, ("process held"));			\
>>> } while (0)
>>>
>>> +#define	PROC_UPDATE_COW(p) do {						\
>>> +	PROC_LOCK_ASSERT((p), MA_OWNED);				\
>>> +	p->p_cowgeneration++;						\
>> Missing parentheses.
> Oops, fixed.
>
>>> +} while (0)
>>> +
>>> /* Check whether a thread is safe to be swapped out. */
>>> #define	thread_safetoswapout(td)	((td)->td_flags & TDF_CANSWAP)
>>>
>>> @@ -976,6 +983,10 @@ struct	thread *thread_alloc(int pages);
>>> int	thread_alloc_stack(struct thread *, int pages);
>>> void	thread_exit(void) __dead2;
>>> void	thread_free(struct thread *td);
>>> +void	thread_get_cow_proc(struct thread *newtd, struct proc *p);
>>> +void	thread_get_cow(struct thread *newtd, struct thread *td);
>>> +void	thread_free_cow(struct thread *td);
>>> +void	thread_update_cow(struct thread *td);
>> Insertion sort errors.
>>
>> Namespace errors.  I don't like the style of naming things with objects
>> first and verbs last, but it is good for sorting related objects.  Here
>> the verbs "get" and "free" are in the middle of the objects
>> "thread_cow_proc" and "thread_cow".  Also, shouldn't it be "thread_proc_cow"
>> (but less verbose, maybe "tpcow"), not "thread_cow_proc", to indicate
>> that the cow is hung of the proc?  I didn't notice the details, but it
>> makes no sense to hang a proc of a cow :-).
>>
> Well all current funcs are named thread_*, so tpcow and the like would
> be inconsistent.
>
> On another look existence of thread_suspend_* suggests thread_cow_*
> naming.
>
> With this putting _proc variant anywhere but at the end also breaks
> consistency. 'thread_cow_from_proc' would increase verbosity.
>
> That said, I would say the patch below is ok enough.
>
> diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
> index 193d207..cef3221 100644
> --- a/sys/amd64/amd64/trap.c
> +++ b/sys/amd64/amd64/trap.c
> @@ -257,8 +257,8 @@ trap(struct trapframe *frame)
>   		td->td_pticks = 0;
>   		td->td_frame = frame;
>   		addr = frame->tf_rip;
> -		if (td->td_ucred != p->p_ucred)
> -			cred_update_thread(td);
> +		if (td->td_cowgen != p->p_cowgen)
> +			thread_cow_update(td);
>   
>   		switch (type) {
>   		case T_PRIVINFLT:	/* privileged instruction fault */
> diff --git a/sys/arm/arm/trap-v6.c b/sys/arm/arm/trap-v6.c
> index abafa86..7463d3c 100644
> --- a/sys/arm/arm/trap-v6.c
> +++ b/sys/arm/arm/trap-v6.c
> @@ -394,8 +394,8 @@ abort_handler(struct trapframe *tf, int prefetch)
>   	p = td->td_proc;
>   	if (usermode) {
>   		td->td_pticks = 0;
> -		if (td->td_ucred != p->p_ucred)
> -			cred_update_thread(td);
> +		if (td->td_cowgen != p->p_cowgen)
> +			thread_cow_update(td);
>   	}
>   
>   	/* Invoke the appropriate handler, if necessary. */
> diff --git a/sys/arm/arm/trap.c b/sys/arm/arm/trap.c
> index 0f142ce..d7fb73a 100644
> --- a/sys/arm/arm/trap.c
> +++ b/sys/arm/arm/trap.c
> @@ -214,8 +214,8 @@ abort_handler(struct trapframe *tf, int type)
>   	if (user) {
>   		td->td_pticks = 0;
>   		td->td_frame = tf;
> -		if (td->td_ucred != td->td_proc->p_ucred)
> -			cred_update_thread(td);
> +		if (td->td_cowgen != td->td_proc->p_cowgen)
> +			thread_cow_update(td);
>   
>   	}
>   	/* Grab the current pcb */
> @@ -644,8 +644,8 @@ prefetch_abort_handler(struct trapframe *tf)
>   
>   	if (TRAP_USERMODE(tf)) {
>   		td->td_frame = tf;
> -		if (td->td_ucred != td->td_proc->p_ucred)
> -			cred_update_thread(td);
> +		if (td->td_cowgen != td->td_proc->p_cowgen)
> +			thread_cow_update(td);
>   	}
>   	fault_pc = tf->tf_pc;
>   	if (td->td_md.md_spinlock_count == 0) {
> diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
> index d783a2b..b118e73 100644
> --- a/sys/i386/i386/trap.c
> +++ b/sys/i386/i386/trap.c
> @@ -306,8 +306,8 @@ trap(struct trapframe *frame)
>   		td->td_pticks = 0;
>   		td->td_frame = frame;
>   		addr = frame->tf_eip;
> -		if (td->td_ucred != p->p_ucred)
> -			cred_update_thread(td);
> +		if (td->td_cowgen != p->p_cowgen)
> +			thread_cow_update(td);
>   
>   		switch (type) {
>   		case T_PRIVINFLT:	/* privileged instruction fault */
> diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
> index b77b788..e0042e9 100644
> --- a/sys/kern/init_main.c
> +++ b/sys/kern/init_main.c
> @@ -522,8 +522,6 @@ proc0_init(void *dummy __unused)
>   #ifdef MAC
>   	mac_cred_create_swapper(newcred);
>   #endif
> -	td->td_ucred = crhold(newcred);
> -
>   	/* Create sigacts. */
>   	p->p_sigacts = sigacts_alloc();
>   
> @@ -555,6 +553,10 @@ proc0_init(void *dummy __unused)
>   	p->p_limit->pl_rlimit[RLIMIT_MEMLOCK].rlim_max = pageablemem;
>   	p->p_cpulimit = RLIM_INFINITY;
>   
> +	PROC_LOCK(p);
> +	thread_cow_get_proc(td, p);
> +	PROC_UNLOCK(p);
> +
>   	/* Initialize resource accounting structures. */
>   	racct_create(&p->p_racct);
>   
> @@ -842,10 +844,10 @@ create_init(const void *udata __unused)
>   	audit_cred_proc1(newcred);
>   #endif
>   	proc_set_cred(initproc, newcred);
> +	cred_update_thread(FIRST_THREAD_IN_PROC(initproc));
>   	PROC_UNLOCK(initproc);
>   	sx_xunlock(&proctree_lock);
>   	crfree(oldcred);
> -	cred_update_thread(FIRST_THREAD_IN_PROC(initproc));
>   	cpu_set_fork_handler(FIRST_THREAD_IN_PROC(initproc), start_init, NULL);
>   }
>   SYSINIT(init, SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL);
> diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
> index c3dd792..0dfecff 100644
> --- a/sys/kern/kern_fork.c
> +++ b/sys/kern/kern_fork.c
> @@ -496,7 +496,6 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
>   	p2->p_swtick = ticks;
>   	if (p1->p_flag & P_PROFIL)
>   		startprofclock(p2);
> -	td2->td_ucred = crhold(p2->p_ucred);
>   
>   	if (flags & RFSIGSHARE) {
>   		p2->p_sigacts = sigacts_hold(p1->p_sigacts);
> @@ -526,6 +525,8 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
>   	 */
>   	lim_fork(p1, p2);
>   
> +	thread_cow_get_proc(td2, p2);
> +
>   	pstats_fork(p1->p_stats, p2->p_stats);
>   
>   	PROC_UNLOCK(p1);
> diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c
> index ee94de0..863bbc6 100644
> --- a/sys/kern/kern_kthread.c
> +++ b/sys/kern/kern_kthread.c
> @@ -289,7 +289,7 @@ kthread_add(void (*func)(void *), void *arg, struct proc *p,
>   	cpu_set_fork_handler(newtd, func, arg);
>   
>   	newtd->td_pflags |= TDP_KTHREAD;
> -	newtd->td_ucred = crhold(p->p_ucred);
> +	thread_cow_get_proc(newtd, p);
>   
>   	/* this code almost the same as create_thread() in kern_thr.c */
>   	p->p_flag |= P_HADTHREADS;
> diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
> index 9c49f71..b531763 100644
> --- a/sys/kern/kern_prot.c
> +++ b/sys/kern/kern_prot.c
> @@ -1946,9 +1946,8 @@ cred_update_thread(struct thread *td)
>   
>   	p = td->td_proc;
>   	cred = td->td_ucred;
> -	PROC_LOCK(p);
> +	PROC_LOCK_ASSERT(p, MA_OWNED);
>   	td->td_ucred = crhold(p->p_ucred);
> -	PROC_UNLOCK(p);
>   	if (cred != NULL)
>   		crfree(cred);
>   }
> @@ -1987,6 +1986,8 @@ proc_set_cred(struct proc *p, struct ucred *newcred)
>   
>   	oldcred = p->p_ucred;
>   	p->p_ucred = newcred;
> +	if (newcred != NULL)
> +		PROC_UPDATE_COW(p);
>   	return (oldcred);
>   }
>   
> diff --git a/sys/kern/kern_syscalls.c b/sys/kern/kern_syscalls.c
> index dada746..3d3df01 100644
> --- a/sys/kern/kern_syscalls.c
> +++ b/sys/kern/kern_syscalls.c
> @@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$");
>   #include <sys/kernel.h>
>   #include <sys/lock.h>
>   #include <sys/module.h>
> +#include <sys/mutex.h>
> +#include <sys/proc.h>
>   #include <sys/sx.h>
>   #include <sys/syscall.h>
>   #include <sys/sysent.h>
> diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c
> index 6911bb97..a53bd25 100644
> --- a/sys/kern/kern_thr.c
> +++ b/sys/kern/kern_thr.c
> @@ -228,13 +228,13 @@ create_thread(struct thread *td, mcontext_t *ctx,
>   	bcopy(&td->td_startcopy, &newtd->td_startcopy,
>   	    __rangeof(struct thread, td_startcopy, td_endcopy));
>   	newtd->td_proc = td->td_proc;
> -	newtd->td_ucred = crhold(td->td_ucred);
> +	thread_cow_get(newtd, td);
>   
>   	if (ctx != NULL) { /* old way to set user context */
>   		error = set_mcontext(newtd, ctx);
>   		if (error != 0) {
> +			thread_cow_free(newtd);
>   			thread_free(newtd);
> -			crfree(td->td_ucred);
>   			goto fail;
>   		}
>   	} else {
> @@ -246,8 +246,8 @@ create_thread(struct thread *td, mcontext_t *ctx,
>   		/* Setup user TLS address and TLS pointer register. */
>   		error = cpu_set_user_tls(newtd, tls_base);
>   		if (error != 0) {
> +			thread_cow_free(newtd);
>   			thread_free(newtd);
> -			crfree(td->td_ucred);
>   			goto fail;
>   		}
>   	}
> diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
> index 0a93dbd..063dfe9 100644
> --- a/sys/kern/kern_thread.c
> +++ b/sys/kern/kern_thread.c
> @@ -324,8 +324,7 @@ thread_reap(void)
>   		mtx_unlock_spin(&zombie_lock);
>   		while (td_first) {
>   			td_next = TAILQ_NEXT(td_first, td_slpq);
> -			if (td_first->td_ucred)
> -				crfree(td_first->td_ucred);
> +			thread_cow_free(td_first);
>   			thread_free(td_first);
>   			td_first = td_next;
>   		}
> @@ -381,6 +380,44 @@ thread_free(struct thread *td)
>   	uma_zfree(thread_zone, td);
>   }
>   
> +void
> +thread_cow_get_proc(struct thread *newtd, struct proc *p)
> +{
> +
> +	PROC_LOCK_ASSERT(p, MA_OWNED);
> +	newtd->td_ucred = crhold(p->p_ucred);
> +	newtd->td_cowgen = p->p_cowgen;
> +}
> +
> +void
> +thread_cow_get(struct thread *newtd, struct thread *td)
> +{
> +
> +	newtd->td_ucred = crhold(td->td_ucred);
> +	newtd->td_cowgen = td->td_cowgen;
> +}
> +
> +void
> +thread_cow_free(struct thread *td)
> +{
> +
> +	if (td->td_ucred)
> +		crfree(td->td_ucred);
> +}
> +
> +void
> +thread_cow_update(struct thread *td)
> +{
> +	struct proc *p;
> +
> +	p = td->td_proc;
> +	PROC_LOCK(p);
> +	if (td->td_ucred != p->p_ucred)
> +		cred_update_thread(td);
> +	td->td_cowgen = p->p_cowgen;
> +	PROC_UNLOCK(p);
> +}
> +
>   /*
>    * Discard the current thread and exit from its context.
>    * Always called with scheduler locked.
> @@ -518,7 +555,7 @@ thread_wait(struct proc *p)
>   	cpuset_rel(td->td_cpuset);
>   	td->td_cpuset = NULL;
>   	cpu_thread_clean(td);
> -	crfree(td->td_ucred);
> +	thread_cow_free(td);
>   	thread_reap();	/* check for zombie threads etc. */
>   }
>   
> diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c
> index 1bf78b8..070ba28 100644
> --- a/sys/kern/subr_syscall.c
> +++ b/sys/kern/subr_syscall.c
> @@ -61,8 +61,8 @@ syscallenter(struct thread *td, struct syscall_args *sa)
>   	p = td->td_proc;
>   
>   	td->td_pticks = 0;
> -	if (td->td_ucred != p->p_ucred)
> -		cred_update_thread(td);
> +	if (td->td_cowgen != p->p_cowgen)
> +		thread_cow_update(td);
>   	if (p->p_flag & P_TRACED) {
>   		traced = 1;
>   		PROC_LOCK(p);
> diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c
> index 93f7557..e5e55dd 100644
> --- a/sys/kern/subr_trap.c
> +++ b/sys/kern/subr_trap.c
> @@ -213,8 +213,8 @@ ast(struct trapframe *framep)
>   	thread_unlock(td);
>   	PCPU_INC(cnt.v_trap);
>   
> -	if (td->td_ucred != p->p_ucred)
> -		cred_update_thread(td);
> +	if (td->td_cowgen != p->p_cowgen)
> +		thread_cow_update(td);
>   	if (td->td_pflags & TDP_OWEUPC && p->p_flag & P_PROFIL) {
>   		addupc_task(td, td->td_profil_addr, td->td_profil_ticks);
>   		td->td_profil_ticks = 0;
> diff --git a/sys/powerpc/powerpc/trap.c b/sys/powerpc/powerpc/trap.c
> index 0ceb170..bfbd94d 100644
> --- a/sys/powerpc/powerpc/trap.c
> +++ b/sys/powerpc/powerpc/trap.c
> @@ -196,8 +196,8 @@ trap(struct trapframe *frame)
>   	if (user) {
>   		td->td_pticks = 0;
>   		td->td_frame = frame;
> -		if (td->td_ucred != p->p_ucred)
> -			cred_update_thread(td);
> +		if (td->td_cowgen != p->p_cowgen)
> +			thread_cow_update(td);
>   
>   		/* User Mode Traps */
>   		switch (type) {
> diff --git a/sys/sparc64/sparc64/trap.c b/sys/sparc64/sparc64/trap.c
> index b4f0e27..e9917e5 100644
> --- a/sys/sparc64/sparc64/trap.c
> +++ b/sys/sparc64/sparc64/trap.c
> @@ -277,8 +277,8 @@ trap(struct trapframe *tf)
>   		td->td_pticks = 0;
>   		td->td_frame = tf;
>   		addr = tf->tf_tpc;
> -		if (td->td_ucred != p->p_ucred)
> -			cred_update_thread(td);
> +		if (td->td_cowgen != p->p_cowgen)
> +			thread_cow_update(td);
>   
>   		switch (tf->tf_type) {
>   		case T_DATA_MISS:
> diff --git a/sys/sys/proc.h b/sys/sys/proc.h
> index 64b99fc..5033957 100644
> --- a/sys/sys/proc.h
> +++ b/sys/sys/proc.h
> @@ -225,6 +225,7 @@ struct thread {
>   /* Cleared during fork1() */
>   #define	td_startzero td_flags
>   	int		td_flags;	/* (t) TDF_* flags. */
> +	u_int		td_cowgen;	/* (k) Generation of COW pointers. */
>   	int		td_inhibitors;	/* (t) Why can not run. */
>   	int		td_pflags;	/* (k) Private thread (TDP_*) flags. */
>   	int		td_dupfd;	/* (k) Ret value from fdopen. XXX */
> @@ -531,6 +532,7 @@ struct proc {
>   	pid_t		p_oppid;	/* (c + e) Save ppid in ptrace. XXX */
>   	struct vmspace	*p_vmspace;	/* (b) Address space. */
>   	u_int		p_swtick;	/* (c) Tick when swapped in or out. */
> +	u_int		p_cowgen;	/* (c) Generation of COW pointers. */
>   	struct itimerval p_realtimer;	/* (c) Alarm timer. */
>   	struct rusage	p_ru;		/* (a) Exit information. */
>   	struct rusage_ext p_rux;	/* (cu) Internal resource usage. */
> @@ -830,6 +832,11 @@ extern pid_t pid_max;
>   	KASSERT((p)->p_lock == 0, ("process held"));			\
>   } while (0)
>   
> +#define	PROC_UPDATE_COW(p) do {						\
> +	PROC_LOCK_ASSERT((p), MA_OWNED);				\
> +	(p)->p_cowgen++;						\
> +} while (0)
> +
>   /* Check whether a thread is safe to be swapped out. */
>   #define	thread_safetoswapout(td)	((td)->td_flags & TDF_CANSWAP)
>   
> @@ -974,6 +981,10 @@ void	cpu_thread_swapin(struct thread *);
>   void	cpu_thread_swapout(struct thread *);
>   struct	thread *thread_alloc(int pages);
>   int	thread_alloc_stack(struct thread *, int pages);
> +void	thread_cow_get_proc(struct thread *newtd, struct proc *p);
> +void	thread_cow_get(struct thread *newtd, struct thread *td);
> +void	thread_cow_free(struct thread *td);
> +void	thread_cow_update(struct thread *td);
>   void	thread_exit(void) __dead2;
>   void	thread_free(struct thread *td);
>   void	thread_link(struct thread *td, struct proc *p);




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?55461CC3.2020306>