]> git.proxmox.com Git - mirror_spl-debian.git/blob - modules/spl/spl-thread.c
Add highbit func,
[mirror_spl-debian.git] / modules / spl / spl-thread.c
1 #include <sys/thread.h>
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
18 static int
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
41 /* DO NOT USE 'ARG' AFTER THIS POINT, EVER, EVER, EVER!
42 * Local variables are used here because after the calling thread
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 }
56 EXPORT_SYMBOL(__thread_exit);
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, int *pp, int state, pri_t pri)
64 {
65 thread_priv_t tp;
66 DEFINE_WAIT(wait);
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)
93 printk(KERN_ERR "Unable to create thread; pid = %ld\n", pid);
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);
108
109 spin_unlock(&tp.tp_lock);
110
111 return (kthread_t *)tp.tp_task;
112 }
113 EXPORT_SYMBOL(__thread_create);