161145dc2SMartin Matuska // SPDX-License-Identifier: GPL-2.0-or-later
2eda14cbcSMatt Macy /*
3eda14cbcSMatt Macy * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
4eda14cbcSMatt Macy * Copyright (C) 2007 The Regents of the University of California.
5eda14cbcSMatt Macy * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
6eda14cbcSMatt Macy * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
7eda14cbcSMatt Macy * UCRL-CODE-235197
8eda14cbcSMatt Macy *
9eda14cbcSMatt Macy * This file is part of the SPL, Solaris Porting Layer.
10eda14cbcSMatt Macy *
11eda14cbcSMatt Macy * The SPL is free software; you can redistribute it and/or modify it
12eda14cbcSMatt Macy * under the terms of the GNU General Public License as published by the
13eda14cbcSMatt Macy * Free Software Foundation; either version 2 of the License, or (at your
14eda14cbcSMatt Macy * option) any later version.
15eda14cbcSMatt Macy *
16eda14cbcSMatt Macy * The SPL is distributed in the hope that it will be useful, but WITHOUT
17eda14cbcSMatt Macy * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18eda14cbcSMatt Macy * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19eda14cbcSMatt Macy * for more details.
20eda14cbcSMatt Macy *
21eda14cbcSMatt Macy * You should have received a copy of the GNU General Public License along
22eda14cbcSMatt Macy * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23eda14cbcSMatt Macy *
24eda14cbcSMatt Macy * Solaris Porting Layer (SPL) Thread Implementation.
25eda14cbcSMatt Macy */
26eda14cbcSMatt Macy
27eda14cbcSMatt Macy #include <sys/thread.h>
28eda14cbcSMatt Macy #include <sys/kmem.h>
29eda14cbcSMatt Macy #include <sys/tsd.h>
30fd45b686SMartin Matuska #include <sys/string.h>
31df58e8b1SMartin Matuska #include <sys/misc.h>
32eda14cbcSMatt Macy
33eda14cbcSMatt Macy /*
34eda14cbcSMatt Macy * Thread interfaces
35eda14cbcSMatt Macy */
36eda14cbcSMatt Macy typedef struct thread_priv_s {
37eda14cbcSMatt Macy unsigned long tp_magic; /* Magic */
38eda14cbcSMatt Macy int tp_name_size; /* Name size */
39eda14cbcSMatt Macy char *tp_name; /* Name (without _thread suffix) */
40eda14cbcSMatt Macy void (*tp_func)(void *); /* Registered function */
41eda14cbcSMatt Macy void *tp_args; /* Args to be passed to function */
42eda14cbcSMatt Macy size_t tp_len; /* Len to be passed to function */
43eda14cbcSMatt Macy int tp_state; /* State to start thread at */
44eda14cbcSMatt Macy pri_t tp_pri; /* Priority to start threat at */
45eda14cbcSMatt Macy } thread_priv_t;
46eda14cbcSMatt Macy
47eda14cbcSMatt Macy static int
thread_generic_wrapper(void * arg)48eda14cbcSMatt Macy thread_generic_wrapper(void *arg)
49eda14cbcSMatt Macy {
50eda14cbcSMatt Macy thread_priv_t *tp = (thread_priv_t *)arg;
51eda14cbcSMatt Macy void (*func)(void *);
52eda14cbcSMatt Macy void *args;
53eda14cbcSMatt Macy
54eda14cbcSMatt Macy ASSERT(tp->tp_magic == TP_MAGIC);
55eda14cbcSMatt Macy func = tp->tp_func;
56eda14cbcSMatt Macy args = tp->tp_args;
57eda14cbcSMatt Macy set_current_state(tp->tp_state);
58eda14cbcSMatt Macy set_user_nice((kthread_t *)current, PRIO_TO_NICE(tp->tp_pri));
59eda14cbcSMatt Macy kmem_free(tp->tp_name, tp->tp_name_size);
60eda14cbcSMatt Macy kmem_free(tp, sizeof (thread_priv_t));
61eda14cbcSMatt Macy
62eda14cbcSMatt Macy if (func)
63eda14cbcSMatt Macy func(args);
64eda14cbcSMatt Macy
65eda14cbcSMatt Macy return (0);
66eda14cbcSMatt Macy }
67eda14cbcSMatt Macy
68eda14cbcSMatt Macy /*
69eda14cbcSMatt Macy * thread_create() may block forever if it cannot create a thread or
70eda14cbcSMatt Macy * allocate memory. This is preferable to returning a NULL which Solaris
71eda14cbcSMatt Macy * style callers likely never check for... since it can't fail.
72eda14cbcSMatt Macy */
73eda14cbcSMatt Macy kthread_t *
__thread_create(caddr_t stk,size_t stksize,thread_func_t func,const char * name,void * args,size_t len,proc_t * pp,int state,pri_t pri)74eda14cbcSMatt Macy __thread_create(caddr_t stk, size_t stksize, thread_func_t func,
75eda14cbcSMatt Macy const char *name, void *args, size_t len, proc_t *pp, int state, pri_t pri)
76eda14cbcSMatt Macy {
77eda14cbcSMatt Macy thread_priv_t *tp;
78eda14cbcSMatt Macy struct task_struct *tsk;
79eda14cbcSMatt Macy char *p;
80eda14cbcSMatt Macy
81eda14cbcSMatt Macy /* Option pp is simply ignored */
82eda14cbcSMatt Macy /* Variable stack size unsupported */
83*d0abb9a6SMartin Matuska ASSERT0P(stk);
84eda14cbcSMatt Macy
85eda14cbcSMatt Macy tp = kmem_alloc(sizeof (thread_priv_t), KM_PUSHPAGE);
86eda14cbcSMatt Macy if (tp == NULL)
87eda14cbcSMatt Macy return (NULL);
88eda14cbcSMatt Macy
89eda14cbcSMatt Macy tp->tp_magic = TP_MAGIC;
90eda14cbcSMatt Macy tp->tp_name_size = strlen(name) + 1;
91eda14cbcSMatt Macy
92eda14cbcSMatt Macy tp->tp_name = kmem_alloc(tp->tp_name_size, KM_PUSHPAGE);
93eda14cbcSMatt Macy if (tp->tp_name == NULL) {
94eda14cbcSMatt Macy kmem_free(tp, sizeof (thread_priv_t));
95eda14cbcSMatt Macy return (NULL);
96eda14cbcSMatt Macy }
97eda14cbcSMatt Macy
98be181ee2SMartin Matuska strlcpy(tp->tp_name, name, tp->tp_name_size);
99eda14cbcSMatt Macy
100eda14cbcSMatt Macy /*
101eda14cbcSMatt Macy * Strip trailing "_thread" from passed name which will be the func
102eda14cbcSMatt Macy * name since the exposed API has no parameter for passing a name.
103eda14cbcSMatt Macy */
104eda14cbcSMatt Macy p = strstr(tp->tp_name, "_thread");
105eda14cbcSMatt Macy if (p)
106eda14cbcSMatt Macy p[0] = '\0';
107eda14cbcSMatt Macy
108eda14cbcSMatt Macy tp->tp_func = func;
109eda14cbcSMatt Macy tp->tp_args = args;
110eda14cbcSMatt Macy tp->tp_len = len;
111eda14cbcSMatt Macy tp->tp_state = state;
112eda14cbcSMatt Macy tp->tp_pri = pri;
113eda14cbcSMatt Macy
114eda14cbcSMatt Macy tsk = spl_kthread_create(thread_generic_wrapper, (void *)tp,
115eda14cbcSMatt Macy "%s", tp->tp_name);
116eda14cbcSMatt Macy if (IS_ERR(tsk))
117eda14cbcSMatt Macy return (NULL);
118eda14cbcSMatt Macy
119eda14cbcSMatt Macy wake_up_process(tsk);
120eda14cbcSMatt Macy return ((kthread_t *)tsk);
121eda14cbcSMatt Macy }
122eda14cbcSMatt Macy EXPORT_SYMBOL(__thread_create);
123eda14cbcSMatt Macy
124eda14cbcSMatt Macy /*
125eda14cbcSMatt Macy * spl_kthread_create - Wrapper providing pre-3.13 semantics for
126eda14cbcSMatt Macy * kthread_create() in which it is not killable and less likely
127eda14cbcSMatt Macy * to return -ENOMEM.
128eda14cbcSMatt Macy */
129eda14cbcSMatt Macy struct task_struct *
spl_kthread_create(int (* func)(void *),void * data,const char namefmt[],...)130eda14cbcSMatt Macy spl_kthread_create(int (*func)(void *), void *data, const char namefmt[], ...)
131eda14cbcSMatt Macy {
132eda14cbcSMatt Macy struct task_struct *tsk;
133eda14cbcSMatt Macy va_list args;
134eda14cbcSMatt Macy char name[TASK_COMM_LEN];
135eda14cbcSMatt Macy
136eda14cbcSMatt Macy va_start(args, namefmt);
137eda14cbcSMatt Macy vsnprintf(name, sizeof (name), namefmt, args);
138eda14cbcSMatt Macy va_end(args);
139eda14cbcSMatt Macy do {
140eda14cbcSMatt Macy tsk = kthread_create(func, data, "%s", name);
141eda14cbcSMatt Macy if (IS_ERR(tsk)) {
142eda14cbcSMatt Macy if (signal_pending(current)) {
143eda14cbcSMatt Macy clear_thread_flag(TIF_SIGPENDING);
144eda14cbcSMatt Macy continue;
145eda14cbcSMatt Macy }
146eda14cbcSMatt Macy if (PTR_ERR(tsk) == -ENOMEM)
147eda14cbcSMatt Macy continue;
148eda14cbcSMatt Macy return (NULL);
149eda14cbcSMatt Macy } else {
150eda14cbcSMatt Macy return (tsk);
151eda14cbcSMatt Macy }
152eda14cbcSMatt Macy } while (1);
153eda14cbcSMatt Macy }
154eda14cbcSMatt Macy EXPORT_SYMBOL(spl_kthread_create);
15516038816SMartin Matuska
15616038816SMartin Matuska /*
157aca928a5SMartin Matuska * Extract the next pending signal from p_sig into p_cursig; stop the process
158aca928a5SMartin Matuska * if a stop has been requested or if a traced signal is pending.
15916038816SMartin Matuska */
16016038816SMartin Matuska int
issig(void)161aca928a5SMartin Matuska issig(void)
16216038816SMartin Matuska {
16316038816SMartin Matuska
16416038816SMartin Matuska if (!signal_pending(current))
16516038816SMartin Matuska return (0);
16616038816SMartin Matuska
16716038816SMartin Matuska spl_kernel_siginfo_t __info;
16816038816SMartin Matuska sigset_t set;
16916038816SMartin Matuska siginitsetinv(&set, 1ULL << (SIGSTOP - 1) | 1ULL << (SIGTSTP - 1));
1707a7741afSMartin Matuska sigorsets(&set, ¤t->blocked, &set);
17116038816SMartin Matuska
1727a7741afSMartin Matuska spin_lock_irq(¤t->sighand->siglock);
1737a7741afSMartin Matuska #if defined(HAVE_DEQUEUE_SIGNAL_4ARG)
174c03c5b1cSMartin Matuska enum pid_type __type;
1757a7741afSMartin Matuska if (dequeue_signal(current, &set, &__info, &__type) != 0) {
1765c65a0a9SMartin Matuska #elif defined(HAVE_DEQUEUE_SIGNAL_3ARG_TYPE)
1777a7741afSMartin Matuska enum pid_type __type;
1787a7741afSMartin Matuska if (dequeue_signal(&set, &__info, &__type) != 0) {
1795c65a0a9SMartin Matuska #else
1805c65a0a9SMartin Matuska if (dequeue_signal(current, &set, &__info) != 0) {
181c03c5b1cSMartin Matuska #endif
18216038816SMartin Matuska spin_unlock_irq(¤t->sighand->siglock);
1837a7741afSMartin Matuska kernel_signal_stop();
18416038816SMartin Matuska
185e2df9bb4SMartin Matuska /*
186e2df9bb4SMartin Matuska * Dequeued SIGSTOP/SIGTSTP.
187e2df9bb4SMartin Matuska * Check if process has other singal pending.
188e2df9bb4SMartin Matuska */
189e2df9bb4SMartin Matuska if (signal_pending(current))
190e2df9bb4SMartin Matuska return (1);
191e2df9bb4SMartin Matuska
19216038816SMartin Matuska return (0);
19316038816SMartin Matuska }
19416038816SMartin Matuska
1957a7741afSMartin Matuska spin_unlock_irq(¤t->sighand->siglock);
19616038816SMartin Matuska
19716038816SMartin Matuska return (1);
19816038816SMartin Matuska }
19916038816SMartin Matuska
20016038816SMartin Matuska EXPORT_SYMBOL(issig);
201df58e8b1SMartin Matuska
202df58e8b1SMartin Matuska /*
203df58e8b1SMartin Matuska * Check if the current thread is a memory reclaim thread.
204df58e8b1SMartin Matuska * Returns true if current thread is kswapd.
205df58e8b1SMartin Matuska */
206df58e8b1SMartin Matuska int
207df58e8b1SMartin Matuska current_is_reclaim_thread(void)
208df58e8b1SMartin Matuska {
209df58e8b1SMartin Matuska return (current_is_kswapd());
210df58e8b1SMartin Matuska }
211df58e8b1SMartin Matuska EXPORT_SYMBOL(current_is_reclaim_thread);
212