kernel - MPSAFE work - add vmspace_token
[dragonfly.git] / sys / sys / thread.h
index 5543e4f..7c65bc4 100644 (file)
@@ -31,6 +31,9 @@
 #ifndef _SYS_SPINLOCK_H_
 #include <sys/spinlock.h>
 #endif
+#ifndef _SYS_IOSCHED_H_
+#include <sys/iosched.h>
+#endif
 #ifndef _MACHINE_THREAD_H_
 #include <machine/thread.h>
 #endif
@@ -95,57 +98,47 @@ struct intrframe;
  * Tokens are managed through a helper reference structure, lwkt_tokref,
  * which is typically declared on the caller's stack.  Multiple tokref's
  * may reference the same token.
- *
- * It is possible to detect that your token was temporarily lost via
- * lwkt_token_is_stale(), which uses the t_lastowner field.  This field
- * does NOT necessarily represent the current owner and can become stale
- * (not point to a valid structure).  It is used solely to detect
- * whether the token was temporarily lost to another thread.  The lost
- * state is cleared by the function.
  */
 
 typedef struct lwkt_token {
-#ifdef SMP
-    struct spinlock    t_spinlock;     /* Controls access */
-#else
-    struct spinlock    t_unused01;
-#endif
-    struct thread      *t_owner;       /* The current owner of the token */
-    int                        t_count;        /* Per-thread count */
-    struct thread       *t_lastowner;  /* Last owner that acquired token */ 
+    struct lwkt_tokref *t_ref;         /* Owning ref or NULL */
+    intptr_t           t_flags;        /* MP lock required */
+    long               t_collisions;   /* Collision counter */
 } lwkt_token;
 
-#ifdef SMP
-#define LWKT_TOKEN_INITIALIZER(head) \
-{ \
-       .t_spinlock = SPINLOCK_INITIALIZER(head.t_spinlock), \
-       .t_owner = NULL, \
-       .t_lastowner = NULL, \
-       .t_count = 0 \
+#define LWKT_TOKEN_MPSAFE      0x0001
+
+/*
+ * Static initialization for a lwkt_token.
+ *     UP - Not MPSAFE (full MP lock will also be acquired)
+ *     MP - Is MPSAFE  (only the token will be acquired)
+ */
+#define LWKT_TOKEN_UP_INITIALIZER      \
+{                                      \
+       .t_ref = NULL,                  \
+       .t_flags = 0,                   \
+       .t_collisions = 0               \
 }
-#else
-#define LWKT_TOKEN_INITIALIZER(head) \
-{ \
-       .t_owner = NULL, \
-       .t_lastowner = NULL, \
-       .t_count = 0 \
+
+#define LWKT_TOKEN_MP_INITIALIZER      \
+{                                      \
+       .t_ref = NULL,                  \
+       .t_flags = LWKT_TOKEN_MPSAFE,   \
+       .t_collisions = 0               \
 }
-#endif
 
-typedef struct lwkt_tokref {
-    lwkt_token_t       tr_tok;         /* token in question */
-    lwkt_tokref_t      tr_next;        /* linked list */
-    int                        tr_state;       /* 0 = don't have, 1 = have */
-} lwkt_tokref;
+#define ASSERT_LWKT_TOKEN_HELD(tok) \
+       KKASSERT((tok)->t_ref->tr_owner == curthread)
 
-#define LWKT_TOKREF_INIT(tok)          \
-                       { tok, NULL, 0 }
-#define LWKT_TOKREF_DECLARE(name, tok) \
-                       lwkt_tokref name = LWKT_TOKREF_INIT(tok)
+struct lwkt_tokref {
+    lwkt_token_t       tr_tok;         /* token in question */
+    struct thread      *tr_owner;      /* me */
+    intptr_t           tr_flags;       /* copy of t_flags */
+};
 
 #define MAXCPUFIFO      16     /* power of 2 */
 #define MAXCPUFIFO_MASK        (MAXCPUFIFO - 1)
-#define LWKT_MAXTOKENS 16      /* max tokens beneficially held by thread */
+#define LWKT_MAXTOKENS 32      /* max tokens beneficially held by thread */
 
 /*
  * Always cast to ipifunc_t when registering an ipi.  The actual ipi function
@@ -205,6 +198,11 @@ typedef struct lwkt_cpu_msg {
  *
  * NOTE: td_pri is bumped by TDPRI_CRIT when entering a critical section,
  * but this does not effect how the thread is scheduled by LWKT.
+ *
+ * NOTE: td_ucred is synchronized from the p_ucred on user->kernel syscall,
+ *      trap, and AST/signal transitions to provide a stable ucred for
+ *      (primarily) system calls.  This field will be NULL for pure kernel
+ *      threads.
  */
 struct md_intr_info;
 struct caps_kinfo;
@@ -212,13 +210,14 @@ struct caps_kinfo;
 struct thread {
     TAILQ_ENTRY(thread) td_threadq;
     TAILQ_ENTRY(thread) td_allq;
+    TAILQ_ENTRY(thread) td_sleepq;
     lwkt_port  td_msgport;     /* built-in message port for replies */
     struct lwp *td_lwp;        /* (optional) associated lwp */
     struct proc        *td_proc;       /* (optional) associated process */
     struct pcb *td_pcb;        /* points to pcb and top of kstack */
     struct globaldata *td_gd;  /* associated with this cpu */
     const char *td_wmesg;      /* string name for blockage */
-    void       *td_wchan;      /* waiting on channel */
+    const volatile void        *td_wchan;      /* waiting on channel */
     int                td_pri;         /* 0-31, 31=highest priority (note 1) */
     int                td_flags;       /* TDF flags */
     int                td_wdomain;     /* domain for wchan address (typ 0) */
@@ -233,6 +232,7 @@ struct thread {
     __uint64_t td_iticks;      /* Statclock hits processing intr (uS) */
     int                td_locks;       /* lockmgr lock debugging */
     int                td_unused01;
+    void       *td_dsched_priv1;       /* priv data for I/O schedulers */
     int                td_refs;        /* hold position in gd_tdallq / hold free */
     int                td_nest_count;  /* prevent splz nesting */
 #ifdef SMP
@@ -242,11 +242,14 @@ struct thread {
     int                td_mpcount_unused;      /* filler so size matches */
     int                td_cscount_unused;
 #endif
+    struct iosched_data td_iosdata;    /* Dynamic I/O scheduling data */
     struct timeval td_start;   /* start time for a thread/process */
     char       td_comm[MAXCOMLEN+1]; /* typ 16+1 bytes */
     struct thread *td_preempted; /* we preempted this thread */
+    struct ucred *td_ucred;            /* synchronized from p_ucred */
     struct caps_kinfo *td_caps;        /* list of client and server registrations */
-    lwkt_tokref_t td_toks;     /* tokens beneficially held */
+    lwkt_tokref_t td_toks_stop;
+    struct lwkt_tokref td_toks_array[LWKT_MAXTOKENS];
 #ifdef DEBUG_CRIT_SECTIONS
 #define CRIT_DEBUG_ARRAY_SIZE   32
 #define CRIT_DEBUG_ARRAY_MASK   (CRIT_DEBUG_ARRAY_SIZE - 1)
@@ -257,6 +260,12 @@ struct thread {
     struct md_thread td_mach;
 };
 
+#define td_toks_base   td_toks_array[0]
+#define td_toks_end    td_toks_array[LWKT_MAXTOKENS]
+
+#define TD_TOKS_HELD(td)       ((td)->td_toks_stop != &(td)->td_toks_base)
+#define TD_TOKS_NOT_HELD(td)   ((td)->td_toks_stop == &(td)->td_toks_base)
+
 /*
  * Thread flags.  Note that TDF_RUNNING is cleared on the old thread after
  * we switch to the new one, which is necessary because LWKTs don't need
@@ -292,7 +301,7 @@ struct thread {
 #define TDF_WAKEREQ            0x4000  /* resume_kproc */
 #define TDF_TIMEOUT            0x8000  /* tsleep timeout */
 #define TDF_INTTHREAD          0x00010000      /* interrupt thread */
-#define TDF_UNUSED20000                0x00020000
+#define TDF_TSLEEP_DESCHEDULED 0x00020000      /* tsleep core deschedule */
 #define TDF_BLOCKED            0x00040000      /* Thread is blocked */
 #define TDF_PANICWARN          0x00080000      /* panic warning in switch */
 #define TDF_BLOCKQ             0x00100000      /* on block queue */
@@ -312,6 +321,7 @@ struct thread {
  * rollup flag will be set in mycpu->gd_reqflags.
  */
 #define TDPRI_IDLE_THREAD      0       /* the idle thread */
+#define TDPRI_IDLE_WORK                1       /* idle work (page zero, etc) */
 #define TDPRI_USER_SCHEDULER   2       /* user scheduler helper */
 #define TDPRI_USER_IDLE                4       /* user scheduler idle */
 #define TDPRI_USER_NORM                6       /* user scheduler normal */
@@ -331,19 +341,34 @@ struct thread {
 #define TDPRI_MASK             31
 #define TDPRI_CRIT             32      /* high bits of td_pri used for crit */
 
-#ifdef _KERNEL
 #define LWKT_THREAD_STACK      (UPAGES * PAGE_SIZE)
-#endif
 
 #define CACHE_NTHREADS         6
 
 #define IN_CRITICAL_SECT(td)   ((td)->td_pri >= TDPRI_CRIT)
 
+#ifdef _KERNEL
+
+/*
+ * Global tokens
+ */
+extern struct lwkt_token pmap_token;
+extern struct lwkt_token dev_token;
+extern struct lwkt_token vm_token;
+extern struct lwkt_token vmspace_token;
+extern struct lwkt_token kvm_token;
+extern struct lwkt_token proc_token;
+extern struct lwkt_token tty_token;
+extern struct lwkt_token vnode_token;
+
+/*
+ * Procedures
+ */
 extern void lwkt_init(void);
 extern struct thread *lwkt_alloc_thread(struct thread *, int, int, int);
 extern void lwkt_init_thread(struct thread *, void *, int, int,
                             struct globaldata *);
-extern void lwkt_set_comm(thread_t, const char *, ...);
+extern void lwkt_set_comm(thread_t, const char *, ...) __printflike(2, 3);
 extern void lwkt_wait_free(struct thread *);
 extern void lwkt_free_thread(struct thread *);
 extern void lwkt_gdinit(struct globaldata *);
@@ -355,27 +380,27 @@ extern void lwkt_schedule_self(thread_t);
 extern void lwkt_deschedule(thread_t);
 extern void lwkt_deschedule_self(thread_t);
 extern void lwkt_yield(void);
-extern void lwkt_yield_quick(void);
+extern void lwkt_user_yield(void);
 extern void lwkt_token_wait(void);
 extern void lwkt_hold(thread_t);
 extern void lwkt_rele(thread_t);
+extern void lwkt_passive_release(thread_t);
 
-extern void lwkt_gettoken(lwkt_tokref_t, lwkt_token_t);
-extern int lwkt_trytoken(lwkt_tokref_t, lwkt_token_t);
-extern void lwkt_gettokref(lwkt_tokref_t);
-extern int  lwkt_trytokref(lwkt_tokref_t);
-extern void lwkt_reltoken(lwkt_tokref_t);
+extern void lwkt_gettoken(lwkt_token_t);
+extern int  lwkt_trytoken(lwkt_token_t);
+extern void lwkt_reltoken(lwkt_token_t);
 extern int  lwkt_getalltokens(thread_t);
 extern void lwkt_relalltokens(thread_t);
 extern void lwkt_drain_token_requests(void);
-extern void lwkt_token_init(lwkt_token_t);
+extern void lwkt_token_init(lwkt_token_t, int);
 extern void lwkt_token_uninit(lwkt_token_t);
-extern int  lwkt_token_is_stale(lwkt_tokref_t);
 
 extern void lwkt_token_pool_init(void);
-extern lwkt_token_t lwkt_token_pool_get(void *);
+extern lwkt_token_t lwkt_token_pool_lookup(void *);
+extern lwkt_token_t lwkt_getpooltoken(void *);
 
 extern void lwkt_setpri(thread_t, int);
+extern void lwkt_setpri_initial(thread_t, int);
 extern void lwkt_setpri_self(int);
 extern int lwkt_check_resched(thread_t);
 extern void lwkt_setcpu_self(struct globaldata *);
@@ -395,9 +420,7 @@ extern int  lwkt_send_ipiq3_mask(cpumask_t, ipifunc3_t, void *, int);
 extern void lwkt_wait_ipiq(struct globaldata *, int);
 extern int  lwkt_seq_ipiq(struct globaldata *);
 extern void lwkt_process_ipiq(void);
-#ifdef _KERNEL
 extern void lwkt_process_ipiq_frame(struct intrframe *);
-#endif
 extern void lwkt_smp_stopped(void);
 extern void lwkt_synchronize_ipiqs(const char *);
 
@@ -413,11 +436,12 @@ extern void crit_panic(void);
 extern struct lwp *lwkt_preempted_proc(void);
 
 extern int  lwkt_create (void (*func)(void *), void *, struct thread **,
-                        struct thread *, int, int, const char *, ...);
+               struct thread *, int, int,
+               const char *, ...) __printflike(7, 8);
 extern void lwkt_exit (void) __dead2;
 extern void lwkt_remove_tdallq (struct thread *);
-extern void lwkt_mp_lock_contested(void);
-extern void lwkt_mp_lock_uncontested(void);
+
+#endif
 
 #endif