2 * This file is part of the SPL: Solaris Porting Layer.
4 * Copyright (c) 2008 Lawrence Livermore National Security, LLC.
5 * Produced at Lawrence Livermore National Laboratory
7 * Brian Behlendorf <behlendorf1@llnl.gov>,
8 * Herb Wartens <wartens2@llnl.gov>,
9 * Jim Garlick <garlick@llnl.gov>
12 * This is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "splat-internal.h"
29 #define SPLAT_SUBSYSTEM_THREAD 0x0600
30 #define SPLAT_THREAD_NAME "thread"
31 #define SPLAT_THREAD_DESC "Kernel Thread Tests"
33 #define SPLAT_THREAD_TEST1_ID 0x0601
34 #define SPLAT_THREAD_TEST1_NAME "create"
35 #define SPLAT_THREAD_TEST1_DESC "Validate thread creation"
37 #define SPLAT_THREAD_TEST2_ID 0x0602
38 #define SPLAT_THREAD_TEST2_NAME "exit"
39 #define SPLAT_THREAD_TEST2_DESC "Validate thread exit"
41 #define SPLAT_THREAD_TEST_MAGIC 0x4488CC00UL
43 typedef struct thread_priv
{
44 unsigned long tp_magic
;
47 wait_queue_head_t tp_waitq
;
52 splat_thread_rc(thread_priv_t
*tp
, int rc
)
56 spin_lock(&tp
->tp_lock
);
57 ret
= (tp
->tp_rc
== rc
);
58 spin_unlock(&tp
->tp_lock
);
64 splat_thread_work1(void *priv
)
66 thread_priv_t
*tp
= (thread_priv_t
*)priv
;
68 spin_lock(&tp
->tp_lock
);
69 ASSERT(tp
->tp_magic
== SPLAT_THREAD_TEST_MAGIC
);
71 spin_unlock(&tp
->tp_lock
);
73 wake_up(&tp
->tp_waitq
);
78 splat_thread_test1(struct file
*file
, void *arg
)
83 tp
.tp_magic
= SPLAT_THREAD_TEST_MAGIC
;
85 spin_lock_init(&tp
.tp_lock
);
86 init_waitqueue_head(&tp
.tp_waitq
);
89 thr
= (kthread_t
*)thread_create(NULL
, 0, splat_thread_work1
, &tp
, 0,
90 &p0
, TS_RUN
, minclsyspri
);
91 /* Must never fail under Solaris, but we check anyway since this
92 * can happen in the linux SPL, we may want to change this behavior */
96 /* Sleep until the thread sets tp.tp_rc == 1 */
97 wait_event(tp
.tp_waitq
, splat_thread_rc(&tp
, 1));
99 splat_vprint(file
, SPLAT_THREAD_TEST1_NAME
, "%s",
100 "Thread successfully started properly\n");
105 splat_thread_work2(void *priv
)
107 thread_priv_t
*tp
= (thread_priv_t
*)priv
;
109 spin_lock(&tp
->tp_lock
);
110 ASSERT(tp
->tp_magic
== SPLAT_THREAD_TEST_MAGIC
);
112 spin_unlock(&tp
->tp_lock
);
114 wake_up(&tp
->tp_waitq
);
117 /* The following code is unreachable when thread_exit() is
118 * working properly, which is exactly what we're testing */
119 spin_lock(&tp
->tp_lock
);
121 spin_unlock(&tp
->tp_lock
);
123 wake_up(&tp
->tp_waitq
);
127 splat_thread_test2(struct file
*file
, void *arg
)
133 tp
.tp_magic
= SPLAT_THREAD_TEST_MAGIC
;
135 spin_lock_init(&tp
.tp_lock
);
136 init_waitqueue_head(&tp
.tp_waitq
);
139 thr
= (kthread_t
*)thread_create(NULL
, 0, splat_thread_work2
, &tp
, 0,
140 &p0
, TS_RUN
, minclsyspri
);
141 /* Must never fail under Solaris, but we check anyway since this
142 * can happen in the linux SPL, we may want to change this behavior */
146 /* Sleep until the thread sets tp.tp_rc == 1 */
147 wait_event(tp
.tp_waitq
, splat_thread_rc(&tp
, 1));
149 /* Sleep until the thread sets tp.tp_rc == 2, or until we hit
150 * the timeout. If thread exit is working properly we should
151 * hit the timeout and never see to.tp_rc == 2. */
152 rc
= wait_event_timeout(tp
.tp_waitq
, splat_thread_rc(&tp
, 2), HZ
/ 10);
155 splat_vprint(file
, SPLAT_THREAD_TEST2_NAME
, "%s",
156 "Thread did not exit properly at thread_exit()\n");
158 splat_vprint(file
, SPLAT_THREAD_TEST2_NAME
, "%s",
159 "Thread successfully exited at thread_exit()\n");
166 splat_thread_init(void)
168 splat_subsystem_t
*sub
;
170 sub
= kmalloc(sizeof(*sub
), GFP_KERNEL
);
174 memset(sub
, 0, sizeof(*sub
));
175 strncpy(sub
->desc
.name
, SPLAT_THREAD_NAME
, SPLAT_NAME_SIZE
);
176 strncpy(sub
->desc
.desc
, SPLAT_THREAD_DESC
, SPLAT_DESC_SIZE
);
177 INIT_LIST_HEAD(&sub
->subsystem_list
);
178 INIT_LIST_HEAD(&sub
->test_list
);
179 spin_lock_init(&sub
->test_lock
);
180 sub
->desc
.id
= SPLAT_SUBSYSTEM_THREAD
;
182 SPLAT_TEST_INIT(sub
, SPLAT_THREAD_TEST1_NAME
, SPLAT_THREAD_TEST1_DESC
,
183 SPLAT_THREAD_TEST1_ID
, splat_thread_test1
);
184 SPLAT_TEST_INIT(sub
, SPLAT_THREAD_TEST2_NAME
, SPLAT_THREAD_TEST2_DESC
,
185 SPLAT_THREAD_TEST2_ID
, splat_thread_test2
);
191 splat_thread_fini(splat_subsystem_t
*sub
)
194 SPLAT_TEST_FINI(sub
, SPLAT_THREAD_TEST2_ID
);
195 SPLAT_TEST_FINI(sub
, SPLAT_THREAD_TEST1_ID
);
201 splat_thread_id(void) {
202 return SPLAT_SUBSYSTEM_THREAD
;