First draft: rewrite of {get|set|swap}context(3)
Marcel Moolenaar
marcel at xcllnt.net
Sun Aug 17 11:50:17 PDT 2003
Gang,
Please review the attached patch and let me know to what extend it
introduces breakages. It is the result of "aggressive engineering"
to provoke comments and further fuel discussion. The reason for this
approach is that we currently do not initialize any fields other than
the mcontext and sigmask and only partially copyin() and copyout()
the contexts (typically only the mcontext and sigmask fields). This
generally is very sensitive to breakages, especially when we intro-
duce flags or need to use any of the spare fields.
getcontext(3): the whole ucontext is zeroed before (partially) filled
and we copyout() all of it. This means that uc_link can only
be set/defined after calling setcontext().
setcontext(3): we copyin() the whole ucontext but partially restore
its fields. The sigmask is restored conditionally based upon
the UCF_SIGMASK flag.
swapcontext(3): we preserve uc_link by doing a partial copyin(). The
context is otherwise zeroed and partially filled. we copyout()
the whole context.
The patch has only been compile-tested.
Shoot...
--
Marcel Moolenaar USPA: A-39004 marcel at xcllnt.net
-------------- next part --------------
Index: kern/kern_context.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_context.c,v
retrieving revision 1.6
diff -u -r1.6 kern_context.c
--- kern/kern_context.c 11 Jun 2003 00:56:55 -0000 1.6
+++ kern/kern_context.c 17 Aug 2003 18:34:51 -0000
@@ -38,13 +38,6 @@
#include <sys/signalvar.h>
#include <sys/ucontext.h>
-/*
- * The first two fields of a ucontext_t are the signal mask and
- * the machine context. The next field is uc_link; we want to
- * avoid destroying the link when copying out contexts.
- */
-#define UC_COPY_SIZE offsetof(ucontext_t, uc_link)
-
#ifndef _SYS_SYSPROTO_H_
struct getcontext_args {
struct __ucontext *ucp;
@@ -65,18 +58,17 @@
getcontext(struct thread *td, struct getcontext_args *uap)
{
ucontext_t uc;
- int ret;
if (uap->ucp == NULL)
- ret = EINVAL;
- else {
- get_mcontext(td, &uc.uc_mcontext, 1);
- PROC_LOCK(td->td_proc);
- uc.uc_sigmask = td->td_sigmask;
- PROC_UNLOCK(td->td_proc);
- ret = copyout(&uc, uap->ucp, UC_COPY_SIZE);
- }
- return (ret);
+ return (EINVAL);
+
+ bzero(&uc, sizeof(uc));
+ get_mcontext(td, &uc.uc_mcontext, 1);
+ PROC_LOCK(td->td_proc);
+ uc.uc_sigmask = td->td_sigmask;
+ PROC_UNLOCK(td->td_proc);
+ uc.uc_flags |= UCF_SIGMASK;
+ return (copyout(&uc, uap->ucp, sizeof(uc)));
}
/*
@@ -86,51 +78,59 @@
setcontext(struct thread *td, struct setcontext_args *uap)
{
ucontext_t uc;
- int ret;
+ int error;
if (uap->ucp == NULL)
- ret = EINVAL;
- else {
- ret = copyin(uap->ucp, &uc, UC_COPY_SIZE);
- if (ret == 0) {
- ret = set_mcontext(td, &uc.uc_mcontext);
- if (ret == 0) {
- SIG_CANTMASK(uc.uc_sigmask);
- PROC_LOCK(td->td_proc);
- td->td_sigmask = uc.uc_sigmask;
- PROC_UNLOCK(td->td_proc);
- }
- }
+ return (EINVAL);
+
+ error = copyin(uap->ucp, &uc, sizeof(uc));
+ if (error)
+ return (error);
+ error = set_mcontext(td, &uc.uc_mcontext);
+ if (error)
+ return (error);
+ if (uc.uc_flags & UCF_SIGMASK) {
+ SIG_CANTMASK(uc.uc_sigmask);
+ PROC_LOCK(td->td_proc);
+ td->td_sigmask = uc.uc_sigmask;
+ PROC_UNLOCK(td->td_proc);
}
- return (ret == 0 ? EJUSTRETURN : ret);
+ return (EJUSTRETURN);
}
int
swapcontext(struct thread *td, struct swapcontext_args *uap)
{
ucontext_t uc;
- int ret;
+ int error;
if (uap->oucp == NULL || uap->ucp == NULL)
- ret = EINVAL;
- else {
- get_mcontext(td, &uc.uc_mcontext, 1);
+ return (EINVAL);
+
+ bzero(&uc, sizeof(uc));
+ error = copyin(uap->oucp + offsetof(ucontext_t, uc_link), &uc.uc_link,
+ sizeof(uc.uc_link));
+ if (error)
+ return (error);
+ get_mcontext(td, &uc.uc_mcontext, 1);
+ PROC_LOCK(td->td_proc);
+ uc.uc_sigmask = td->td_sigmask;
+ PROC_UNLOCK(td->td_proc);
+ uc.uc_flags |= UCF_SIGMASK;
+ error = copyout(&uc, uap->oucp, sizeof(uc));
+ if (error)
+ return (error);
+ error = copyin(uap->ucp, &uc, sizeof(uc));
+ if (error)
+ return (error);
+ error = set_mcontext(td, &uc.uc_mcontext);
+ if (error)
+ return (error);
+ if (uc.uc_flags & UCF_SIGMASK) {
+ SIG_CANTMASK(uc.uc_sigmask);
PROC_LOCK(td->td_proc);
- uc.uc_sigmask = td->td_sigmask;
+ td->td_sigmask = uc.uc_sigmask;
PROC_UNLOCK(td->td_proc);
- ret = copyout(&uc, uap->oucp, UC_COPY_SIZE);
- if (ret == 0) {
- ret = copyin(uap->ucp, &uc, UC_COPY_SIZE);
- if (ret == 0) {
- ret = set_mcontext(td, &uc.uc_mcontext);
- if (ret == 0) {
- SIG_CANTMASK(uc.uc_sigmask);
- PROC_LOCK(td->td_proc);
- td->td_sigmask = uc.uc_sigmask;
- PROC_UNLOCK(td->td_proc);
- }
- }
- }
}
- return (ret == 0 ? EJUSTRETURN : ret);
+ return (EJUSTRETURN);
}
Index: sys/ucontext.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/ucontext.h,v
retrieving revision 1.10
diff -u -r1.10 ucontext.h
--- sys/ucontext.h 25 Apr 2003 01:50:30 -0000 1.10
+++ sys/ucontext.h 17 Aug 2003 18:13:49 -0000
@@ -34,6 +34,18 @@
#include <sys/signal.h>
#include <machine/ucontext.h>
+/*
+ * A note about UCF_SIGMASK: Contexts are defined in ucontext(3) to include
+ * the signal mask (ie blocked signals). By default getcontext(3) creates
+ * contexts according to that definition and setcontext(3) will restore it.
+ * Our 1:1 and M:N threading libraries use the ucontext structure without
+ * taking the signal mask into account. They either not restore it, not
+ * define it or both. Since contexts in the M:N library are shared between
+ * the kernel and the threaded application, there's a need to mark contexts
+ * that do have a valid signal mask so that setcontext(3) knows when to
+ * restore it.
+ */
+
typedef struct __ucontext {
/*
* Keep the order of the first two fields. Also,
@@ -49,7 +61,7 @@
struct __ucontext *uc_link;
stack_t uc_stack;
int uc_flags;
-#define UCF_SWAPPED 0x00000001 /* Used by swapcontext(3). */
+#define UCF_SIGMASK 0x00000001 /* Context has valid signal mask. */
int __spare__[4];
} ucontext_t;
More information about the freebsd-threads
mailing list