]> git.proxmox.com Git - mirror_spl-debian.git/blob - module/splat/splat-thread.c
Public Release Prep
[mirror_spl-debian.git] / module / splat / splat-thread.c
1 /*****************************************************************************\
2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2007 The Regents of the University of California.
4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
6 * UCRL-CODE-235197
7 *
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://github.com/behlendorf/spl/>.
10 *
11 * The SPL is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 *
16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting LAyer Tests (SPLAT) Thread Tests.
25 \*****************************************************************************/
26
27 #include "splat-internal.h"
28
29 #define SPLAT_THREAD_NAME "thread"
30 #define SPLAT_THREAD_DESC "Kernel Thread Tests"
31
32 #define SPLAT_THREAD_TEST1_ID 0x0601
33 #define SPLAT_THREAD_TEST1_NAME "create"
34 #define SPLAT_THREAD_TEST1_DESC "Validate thread creation"
35
36 #define SPLAT_THREAD_TEST2_ID 0x0602
37 #define SPLAT_THREAD_TEST2_NAME "exit"
38 #define SPLAT_THREAD_TEST2_DESC "Validate thread exit"
39
40 #define SPLAT_THREAD_TEST_MAGIC 0x4488CC00UL
41
42 typedef struct thread_priv {
43 unsigned long tp_magic;
44 struct file *tp_file;
45 spinlock_t tp_lock;
46 wait_queue_head_t tp_waitq;
47 int tp_rc;
48 } thread_priv_t;
49
50 static int
51 splat_thread_rc(thread_priv_t *tp, int rc)
52 {
53 int ret;
54
55 spin_lock(&tp->tp_lock);
56 ret = (tp->tp_rc == rc);
57 spin_unlock(&tp->tp_lock);
58
59 return ret;
60 }
61
62 static void
63 splat_thread_work1(void *priv)
64 {
65 thread_priv_t *tp = (thread_priv_t *)priv;
66
67 spin_lock(&tp->tp_lock);
68 ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC);
69 tp->tp_rc = 1;
70 spin_unlock(&tp->tp_lock);
71
72 wake_up(&tp->tp_waitq);
73 thread_exit();
74 }
75
76 static int
77 splat_thread_test1(struct file *file, void *arg)
78 {
79 thread_priv_t tp;
80 kthread_t *thr;
81
82 tp.tp_magic = SPLAT_THREAD_TEST_MAGIC;
83 tp.tp_file = file;
84 spin_lock_init(&tp.tp_lock);
85 init_waitqueue_head(&tp.tp_waitq);
86 tp.tp_rc = 0;
87
88 thr = (kthread_t *)thread_create(NULL, 0, splat_thread_work1, &tp, 0,
89 &p0, TS_RUN, minclsyspri);
90 /* Must never fail under Solaris, but we check anyway since this
91 * can happen in the linux SPL, we may want to change this behavior */
92 if (thr == NULL)
93 return -ESRCH;
94
95 /* Sleep until the thread sets tp.tp_rc == 1 */
96 wait_event(tp.tp_waitq, splat_thread_rc(&tp, 1));
97
98 splat_vprint(file, SPLAT_THREAD_TEST1_NAME, "%s",
99 "Thread successfully started properly\n");
100 return 0;
101 }
102
103 static void
104 splat_thread_work2(void *priv)
105 {
106 thread_priv_t *tp = (thread_priv_t *)priv;
107
108 spin_lock(&tp->tp_lock);
109 ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC);
110 tp->tp_rc = 1;
111 spin_unlock(&tp->tp_lock);
112
113 wake_up(&tp->tp_waitq);
114 thread_exit();
115
116 /* The following code is unreachable when thread_exit() is
117 * working properly, which is exactly what we're testing */
118 spin_lock(&tp->tp_lock);
119 tp->tp_rc = 2;
120 spin_unlock(&tp->tp_lock);
121
122 wake_up(&tp->tp_waitq);
123 }
124
125 static int
126 splat_thread_test2(struct file *file, void *arg)
127 {
128 thread_priv_t tp;
129 kthread_t *thr;
130 int rc = 0;
131
132 tp.tp_magic = SPLAT_THREAD_TEST_MAGIC;
133 tp.tp_file = file;
134 spin_lock_init(&tp.tp_lock);
135 init_waitqueue_head(&tp.tp_waitq);
136 tp.tp_rc = 0;
137
138 thr = (kthread_t *)thread_create(NULL, 0, splat_thread_work2, &tp, 0,
139 &p0, TS_RUN, minclsyspri);
140 /* Must never fail under Solaris, but we check anyway since this
141 * can happen in the linux SPL, we may want to change this behavior */
142 if (thr == NULL)
143 return -ESRCH;
144
145 /* Sleep until the thread sets tp.tp_rc == 1 */
146 wait_event(tp.tp_waitq, splat_thread_rc(&tp, 1));
147
148 /* Sleep until the thread sets tp.tp_rc == 2, or until we hit
149 * the timeout. If thread exit is working properly we should
150 * hit the timeout and never see to.tp_rc == 2. */
151 rc = wait_event_timeout(tp.tp_waitq, splat_thread_rc(&tp, 2), HZ / 10);
152 if (rc > 0) {
153 rc = -EINVAL;
154 splat_vprint(file, SPLAT_THREAD_TEST2_NAME, "%s",
155 "Thread did not exit properly at thread_exit()\n");
156 } else {
157 splat_vprint(file, SPLAT_THREAD_TEST2_NAME, "%s",
158 "Thread successfully exited at thread_exit()\n");
159 }
160
161 return rc;
162 }
163
164 splat_subsystem_t *
165 splat_thread_init(void)
166 {
167 splat_subsystem_t *sub;
168
169 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
170 if (sub == NULL)
171 return NULL;
172
173 memset(sub, 0, sizeof(*sub));
174 strncpy(sub->desc.name, SPLAT_THREAD_NAME, SPLAT_NAME_SIZE);
175 strncpy(sub->desc.desc, SPLAT_THREAD_DESC, SPLAT_DESC_SIZE);
176 INIT_LIST_HEAD(&sub->subsystem_list);
177 INIT_LIST_HEAD(&sub->test_list);
178 spin_lock_init(&sub->test_lock);
179 sub->desc.id = SPLAT_SUBSYSTEM_THREAD;
180
181 SPLAT_TEST_INIT(sub, SPLAT_THREAD_TEST1_NAME, SPLAT_THREAD_TEST1_DESC,
182 SPLAT_THREAD_TEST1_ID, splat_thread_test1);
183 SPLAT_TEST_INIT(sub, SPLAT_THREAD_TEST2_NAME, SPLAT_THREAD_TEST2_DESC,
184 SPLAT_THREAD_TEST2_ID, splat_thread_test2);
185
186 return sub;
187 }
188
189 void
190 splat_thread_fini(splat_subsystem_t *sub)
191 {
192 ASSERT(sub);
193 SPLAT_TEST_FINI(sub, SPLAT_THREAD_TEST2_ID);
194 SPLAT_TEST_FINI(sub, SPLAT_THREAD_TEST1_ID);
195
196 kfree(sub);
197 }
198
199 int
200 splat_thread_id(void) {
201 return SPLAT_SUBSYSTEM_THREAD;
202 }