]>
Commit | Line | Data |
---|---|---|
f4b37741 | 1 | #include <sys/thread.h> |
f1ca4da6 | 2 | |
3 | /* | |
4 | * Thread interfaces | |
5 | */ | |
6 | typedef struct thread_priv_s { | |
7 | unsigned long tp_magic; /* Magic */ | |
8 | void (*tp_func)(void *); /* Registered function */ | |
9 | void *tp_args; /* Args to be passed to function */ | |
10 | size_t tp_len; /* Len to be passed to function */ | |
11 | int tp_state; /* State to start thread at */ | |
12 | pri_t tp_pri; /* Priority to start threat at */ | |
13 | volatile kthread_t *tp_task; /* Task pointer for new thread */ | |
14 | spinlock_t tp_lock; /* Syncronization lock */ | |
15 | wait_queue_head_t tp_waitq; /* Syncronization wait queue */ | |
16 | } thread_priv_t; | |
17 | ||
f1b59d26 | 18 | static int |
f1ca4da6 | 19 | thread_generic_wrapper(void *arg) |
20 | { | |
21 | thread_priv_t *tp = (thread_priv_t *)arg; | |
22 | void (*func)(void *); | |
23 | void *args; | |
24 | char name[16]; | |
25 | ||
26 | /* Use the truncated function name as thread name */ | |
27 | snprintf(name, sizeof(name), "%s", "kthread"); | |
28 | daemonize(name); | |
29 | ||
30 | spin_lock(&tp->tp_lock); | |
31 | BUG_ON(tp->tp_magic != TP_MAGIC); | |
32 | func = tp->tp_func; | |
33 | args = tp->tp_args; | |
34 | tp->tp_task = get_current(); | |
35 | set_current_state(tp->tp_state); | |
36 | set_user_nice((kthread_t *)tp->tp_task, PRIO_TO_NICE(tp->tp_pri)); | |
37 | ||
38 | spin_unlock(&tp->tp_lock); | |
39 | wake_up(&tp->tp_waitq); | |
40 | ||
f1b59d26 | 41 | /* DO NOT USE 'ARG' AFTER THIS POINT, EVER, EVER, EVER! |
42 | * Local variables are used here because after the calling thread | |
f1ca4da6 | 43 | * has been woken up it will exit and this memory will no longer |
44 | * be safe to access since it was declared on the callers stack. */ | |
45 | if (func) | |
46 | func(args); | |
47 | ||
48 | return 0; | |
49 | } | |
50 | ||
51 | void | |
52 | __thread_exit(void) | |
53 | { | |
54 | return; | |
55 | } | |
f1b59d26 | 56 | EXPORT_SYMBOL(__thread_exit); |
f1ca4da6 | 57 | |
58 | /* thread_create() may block forever if it cannot create a thread or | |
59 | * allocate memory. This is preferable to returning a NULL which Solaris | |
60 | * style callers likely never check for... since it can't fail. */ | |
61 | kthread_t * | |
62 | __thread_create(caddr_t stk, size_t stksize, void (*proc)(void *), | |
63 | void *args, size_t len, proc_t *pp, int state, pri_t pri) | |
64 | { | |
65 | thread_priv_t tp; | |
66 | DEFINE_WAIT(wait); | |
f1ca4da6 | 67 | long pid; |
68 | ||
69 | /* Option pp is simply ignored */ | |
70 | /* Variable stack size unsupported */ | |
71 | BUG_ON(stk != NULL); | |
72 | BUG_ON(stk != 0); | |
73 | ||
74 | /* Variable tp is located on the stack and not the heap because I want | |
75 | * to minimize any chance of a failure, since the Solaris code is designed | |
76 | * such that this function cannot fail. This is a little dangerous since | |
77 | * we're passing a stack address to a new thread but correct locking was | |
78 | * added to ensure the callee can use the data safely until wake_up(). */ | |
79 | tp.tp_magic = TP_MAGIC; | |
80 | tp.tp_func = proc; | |
81 | tp.tp_args = args; | |
82 | tp.tp_len = len; | |
83 | tp.tp_state = state; | |
84 | tp.tp_pri = pri; | |
85 | tp.tp_task = NULL; | |
86 | spin_lock_init(&tp.tp_lock); | |
87 | init_waitqueue_head(&tp.tp_waitq); | |
88 | ||
89 | spin_lock(&tp.tp_lock); | |
90 | ||
91 | /* Solaris says this must never fail so we try forever */ | |
92 | while ((pid = kernel_thread(thread_generic_wrapper, (void *)&tp, 0)) < 0) | |
596e65b4 | 93 | printk(KERN_ERR "Unable to create thread; pid = %ld\n", pid); |
f1ca4da6 | 94 | |
95 | /* All signals are ignored due to sleeping TASK_UNINTERRUPTIBLE */ | |
96 | for (;;) { | |
97 | prepare_to_wait(&tp.tp_waitq, &wait, TASK_UNINTERRUPTIBLE); | |
98 | if (tp.tp_task != NULL) | |
99 | break; | |
100 | ||
101 | spin_unlock(&tp.tp_lock); | |
102 | schedule(); | |
103 | spin_lock(&tp.tp_lock); | |
104 | } | |
105 | ||
106 | /* Verify the pid retunred matches the pid in the task struct */ | |
107 | BUG_ON(pid != (tp.tp_task)->pid); | |
f1b59d26 | 108 | |
f1ca4da6 | 109 | spin_unlock(&tp.tp_lock); |
110 | ||
111 | return (kthread_t *)tp.tp_task; | |
112 | } | |
f1b59d26 | 113 | EXPORT_SYMBOL(__thread_create); |