1*eda14cbcSMatt Macy /* 2*eda14cbcSMatt Macy * CDDL HEADER START 3*eda14cbcSMatt Macy * 4*eda14cbcSMatt Macy * This file and its contents are supplied under the terms of the 5*eda14cbcSMatt Macy * Common Development and Distribution License ("CDDL"), version 1.0. 6*eda14cbcSMatt Macy * You may only use this file in accordance with the terms of version 7*eda14cbcSMatt Macy * 1.0 of the CDDL. 8*eda14cbcSMatt Macy * 9*eda14cbcSMatt Macy * A full copy of the text of the CDDL should have accompanied this 10*eda14cbcSMatt Macy * source. A copy of the CDDL is also available via the Internet at 11*eda14cbcSMatt Macy * http://www.illumos.org/license/CDDL. 12*eda14cbcSMatt Macy * 13*eda14cbcSMatt Macy * CDDL HEADER END 14*eda14cbcSMatt Macy */ 15*eda14cbcSMatt Macy 16*eda14cbcSMatt Macy /* 17*eda14cbcSMatt Macy * Copyright (c) 2017, 2020 by Delphix. All rights reserved. 18*eda14cbcSMatt Macy */ 19*eda14cbcSMatt Macy 20*eda14cbcSMatt Macy /* 21*eda14cbcSMatt Macy * ZTHR Infrastructure 22*eda14cbcSMatt Macy * =================== 23*eda14cbcSMatt Macy * 24*eda14cbcSMatt Macy * ZTHR threads are used for isolated operations that span multiple txgs 25*eda14cbcSMatt Macy * within a SPA. They generally exist from SPA creation/loading and until 26*eda14cbcSMatt Macy * the SPA is exported/destroyed. The ideal requirements for an operation 27*eda14cbcSMatt Macy * to be modeled with a zthr are the following: 28*eda14cbcSMatt Macy * 29*eda14cbcSMatt Macy * 1] The operation needs to run over multiple txgs. 30*eda14cbcSMatt Macy * 2] There is be a single point of reference in memory or on disk that 31*eda14cbcSMatt Macy * indicates whether the operation should run/is running or has 32*eda14cbcSMatt Macy * stopped. 33*eda14cbcSMatt Macy * 34*eda14cbcSMatt Macy * If the operation satisfies the above then the following rules guarantee 35*eda14cbcSMatt Macy * a certain level of correctness: 36*eda14cbcSMatt Macy * 37*eda14cbcSMatt Macy * 1] Any thread EXCEPT the zthr changes the work indicator from stopped 38*eda14cbcSMatt Macy * to running but not the opposite. 39*eda14cbcSMatt Macy * 2] Only the zthr can change the work indicator from running to stopped 40*eda14cbcSMatt Macy * (e.g. when it is done) but not the opposite. 41*eda14cbcSMatt Macy * 42*eda14cbcSMatt Macy * This way a normal zthr cycle should go like this: 43*eda14cbcSMatt Macy * 44*eda14cbcSMatt Macy * 1] An external thread changes the work indicator from stopped to 45*eda14cbcSMatt Macy * running and wakes up the zthr. 46*eda14cbcSMatt Macy * 2] The zthr wakes up, checks the indicator and starts working. 47*eda14cbcSMatt Macy * 3] When the zthr is done, it changes the indicator to stopped, allowing 48*eda14cbcSMatt Macy * a new cycle to start. 49*eda14cbcSMatt Macy * 50*eda14cbcSMatt Macy * Besides being awakened by other threads, a zthr can be configured 51*eda14cbcSMatt Macy * during creation to wakeup on its own after a specified interval 52*eda14cbcSMatt Macy * [see zthr_create_timer()]. 53*eda14cbcSMatt Macy * 54*eda14cbcSMatt Macy * Note: ZTHR threads are NOT a replacement for generic threads! Please 55*eda14cbcSMatt Macy * ensure that they fit your use-case well before using them. 56*eda14cbcSMatt Macy * 57*eda14cbcSMatt Macy * == ZTHR creation 58*eda14cbcSMatt Macy * 59*eda14cbcSMatt Macy * Every zthr needs three inputs to start running: 60*eda14cbcSMatt Macy * 61*eda14cbcSMatt Macy * 1] A user-defined checker function (checkfunc) that decides whether 62*eda14cbcSMatt Macy * the zthr should start working or go to sleep. The function should 63*eda14cbcSMatt Macy * return TRUE when the zthr needs to work or FALSE to let it sleep, 64*eda14cbcSMatt Macy * and should adhere to the following signature: 65*eda14cbcSMatt Macy * boolean_t checkfunc_name(void *args, zthr_t *t); 66*eda14cbcSMatt Macy * 67*eda14cbcSMatt Macy * 2] A user-defined ZTHR function (func) which the zthr executes when 68*eda14cbcSMatt Macy * it is not sleeping. The function should adhere to the following 69*eda14cbcSMatt Macy * signature type: 70*eda14cbcSMatt Macy * void func_name(void *args, zthr_t *t); 71*eda14cbcSMatt Macy * 72*eda14cbcSMatt Macy * 3] A void args pointer that will be passed to checkfunc and func 73*eda14cbcSMatt Macy * implicitly by the infrastructure. 74*eda14cbcSMatt Macy * 75*eda14cbcSMatt Macy * The reason why the above API needs two different functions, 76*eda14cbcSMatt Macy * instead of one that both checks and does the work, has to do with 77*eda14cbcSMatt Macy * the zthr's internal state lock (zthr_state_lock) and the allowed 78*eda14cbcSMatt Macy * cancellation windows. We want to hold the zthr_state_lock while 79*eda14cbcSMatt Macy * running checkfunc but not while running func. This way the zthr 80*eda14cbcSMatt Macy * can be cancelled while doing work and not while checking for work. 81*eda14cbcSMatt Macy * 82*eda14cbcSMatt Macy * To start a zthr: 83*eda14cbcSMatt Macy * zthr_t *zthr_pointer = zthr_create(checkfunc, func, args); 84*eda14cbcSMatt Macy * or 85*eda14cbcSMatt Macy * zthr_t *zthr_pointer = zthr_create_timer(checkfunc, func, 86*eda14cbcSMatt Macy * args, max_sleep); 87*eda14cbcSMatt Macy * 88*eda14cbcSMatt Macy * After that you should be able to wakeup, cancel, and resume the 89*eda14cbcSMatt Macy * zthr from another thread using the zthr_pointer. 90*eda14cbcSMatt Macy * 91*eda14cbcSMatt Macy * NOTE: ZTHR threads could potentially wake up spuriously and the 92*eda14cbcSMatt Macy * user should take this into account when writing a checkfunc. 93*eda14cbcSMatt Macy * [see ZTHR state transitions] 94*eda14cbcSMatt Macy * 95*eda14cbcSMatt Macy * == ZTHR wakeup 96*eda14cbcSMatt Macy * 97*eda14cbcSMatt Macy * ZTHR wakeup should be used when new work is added for the zthr. The 98*eda14cbcSMatt Macy * sleeping zthr will wakeup, see that it has more work to complete 99*eda14cbcSMatt Macy * and proceed. This can be invoked from open or syncing context. 100*eda14cbcSMatt Macy * 101*eda14cbcSMatt Macy * To wakeup a zthr: 102*eda14cbcSMatt Macy * zthr_wakeup(zthr_t *t) 103*eda14cbcSMatt Macy * 104*eda14cbcSMatt Macy * == ZTHR cancellation and resumption 105*eda14cbcSMatt Macy * 106*eda14cbcSMatt Macy * ZTHR threads must be cancelled when their SPA is being exported 107*eda14cbcSMatt Macy * or when they need to be paused so they don't interfere with other 108*eda14cbcSMatt Macy * operations. 109*eda14cbcSMatt Macy * 110*eda14cbcSMatt Macy * To cancel a zthr: 111*eda14cbcSMatt Macy * zthr_cancel(zthr_pointer); 112*eda14cbcSMatt Macy * 113*eda14cbcSMatt Macy * To resume it: 114*eda14cbcSMatt Macy * zthr_resume(zthr_pointer); 115*eda14cbcSMatt Macy * 116*eda14cbcSMatt Macy * ZTHR cancel and resume should be invoked in open context during the 117*eda14cbcSMatt Macy * lifecycle of the pool as it is imported, exported or destroyed. 118*eda14cbcSMatt Macy * 119*eda14cbcSMatt Macy * A zthr will implicitly check if it has received a cancellation 120*eda14cbcSMatt Macy * signal every time func returns and every time it wakes up [see 121*eda14cbcSMatt Macy * ZTHR state transitions below]. 122*eda14cbcSMatt Macy * 123*eda14cbcSMatt Macy * At times, waiting for the zthr's func to finish its job may take 124*eda14cbcSMatt Macy * time. This may be very time-consuming for some operations that 125*eda14cbcSMatt Macy * need to cancel the SPA's zthrs (e.g spa_export). For this scenario 126*eda14cbcSMatt Macy * the user can explicitly make their ZTHR function aware of incoming 127*eda14cbcSMatt Macy * cancellation signals using zthr_iscancelled(). A common pattern for 128*eda14cbcSMatt Macy * that looks like this: 129*eda14cbcSMatt Macy * 130*eda14cbcSMatt Macy * int 131*eda14cbcSMatt Macy * func_name(void *args, zthr_t *t) 132*eda14cbcSMatt Macy * { 133*eda14cbcSMatt Macy * ... <unpack args> ... 134*eda14cbcSMatt Macy * while (!work_done && !zthr_iscancelled(t)) { 135*eda14cbcSMatt Macy * ... <do more work> ... 136*eda14cbcSMatt Macy * } 137*eda14cbcSMatt Macy * } 138*eda14cbcSMatt Macy * 139*eda14cbcSMatt Macy * == ZTHR cleanup 140*eda14cbcSMatt Macy * 141*eda14cbcSMatt Macy * Cancelling a zthr doesn't clean up its metadata (internal locks, 142*eda14cbcSMatt Macy * function pointers to func and checkfunc, etc..). This is because 143*eda14cbcSMatt Macy * we want to keep them around in case we want to resume the execution 144*eda14cbcSMatt Macy * of the zthr later. Similarly for zthrs that exit themselves. 145*eda14cbcSMatt Macy * 146*eda14cbcSMatt Macy * To completely cleanup a zthr, cancel it first to ensure that it 147*eda14cbcSMatt Macy * is not running and then use zthr_destroy(). 148*eda14cbcSMatt Macy * 149*eda14cbcSMatt Macy * == ZTHR state transitions 150*eda14cbcSMatt Macy * 151*eda14cbcSMatt Macy * zthr creation 152*eda14cbcSMatt Macy * + 153*eda14cbcSMatt Macy * | 154*eda14cbcSMatt Macy * | woke up 155*eda14cbcSMatt Macy * | +--------------+ sleep 156*eda14cbcSMatt Macy * | | ^ 157*eda14cbcSMatt Macy * | | | 158*eda14cbcSMatt Macy * | | | FALSE 159*eda14cbcSMatt Macy * | | | 160*eda14cbcSMatt Macy * v v FALSE + 161*eda14cbcSMatt Macy * cancelled? +---------> checkfunc? 162*eda14cbcSMatt Macy * + ^ + 163*eda14cbcSMatt Macy * | | | 164*eda14cbcSMatt Macy * | | | TRUE 165*eda14cbcSMatt Macy * | | | 166*eda14cbcSMatt Macy * | | func returned v 167*eda14cbcSMatt Macy * | +---------------+ func 168*eda14cbcSMatt Macy * | 169*eda14cbcSMatt Macy * | TRUE 170*eda14cbcSMatt Macy * | 171*eda14cbcSMatt Macy * v 172*eda14cbcSMatt Macy * zthr stopped running 173*eda14cbcSMatt Macy * 174*eda14cbcSMatt Macy * == Implementation of ZTHR requests 175*eda14cbcSMatt Macy * 176*eda14cbcSMatt Macy * ZTHR cancel and resume are requests on a zthr to change its 177*eda14cbcSMatt Macy * internal state. These requests are serialized using the 178*eda14cbcSMatt Macy * zthr_request_lock, while changes in its internal state are 179*eda14cbcSMatt Macy * protected by the zthr_state_lock. A request will first acquire 180*eda14cbcSMatt Macy * the zthr_request_lock and then immediately acquire the 181*eda14cbcSMatt Macy * zthr_state_lock. We do this so that incoming requests are 182*eda14cbcSMatt Macy * serialized using the request lock, while still allowing us 183*eda14cbcSMatt Macy * to use the state lock for thread communication via zthr_cv. 184*eda14cbcSMatt Macy * 185*eda14cbcSMatt Macy * ZTHR wakeup broadcasts to zthr_cv, causing sleeping threads 186*eda14cbcSMatt Macy * to wakeup. It acquires the zthr_state_lock but not the 187*eda14cbcSMatt Macy * zthr_request_lock, so that a wakeup on a zthr in the middle 188*eda14cbcSMatt Macy * of being cancelled will not block. 189*eda14cbcSMatt Macy */ 190*eda14cbcSMatt Macy 191*eda14cbcSMatt Macy #include <sys/zfs_context.h> 192*eda14cbcSMatt Macy #include <sys/zthr.h> 193*eda14cbcSMatt Macy 194*eda14cbcSMatt Macy struct zthr { 195*eda14cbcSMatt Macy /* running thread doing the work */ 196*eda14cbcSMatt Macy kthread_t *zthr_thread; 197*eda14cbcSMatt Macy 198*eda14cbcSMatt Macy /* lock protecting internal data & invariants */ 199*eda14cbcSMatt Macy kmutex_t zthr_state_lock; 200*eda14cbcSMatt Macy 201*eda14cbcSMatt Macy /* mutex that serializes external requests */ 202*eda14cbcSMatt Macy kmutex_t zthr_request_lock; 203*eda14cbcSMatt Macy 204*eda14cbcSMatt Macy /* notification mechanism for requests */ 205*eda14cbcSMatt Macy kcondvar_t zthr_cv; 206*eda14cbcSMatt Macy 207*eda14cbcSMatt Macy /* flag set to true if we are canceling the zthr */ 208*eda14cbcSMatt Macy boolean_t zthr_cancel; 209*eda14cbcSMatt Macy 210*eda14cbcSMatt Macy /* flag set to true if we are waiting for the zthr to finish */ 211*eda14cbcSMatt Macy boolean_t zthr_haswaiters; 212*eda14cbcSMatt Macy kcondvar_t zthr_wait_cv; 213*eda14cbcSMatt Macy /* 214*eda14cbcSMatt Macy * maximum amount of time that the zthr is spent sleeping; 215*eda14cbcSMatt Macy * if this is 0, the thread doesn't wake up until it gets 216*eda14cbcSMatt Macy * signaled. 217*eda14cbcSMatt Macy */ 218*eda14cbcSMatt Macy hrtime_t zthr_sleep_timeout; 219*eda14cbcSMatt Macy 220*eda14cbcSMatt Macy /* consumer-provided callbacks & data */ 221*eda14cbcSMatt Macy zthr_checkfunc_t *zthr_checkfunc; 222*eda14cbcSMatt Macy zthr_func_t *zthr_func; 223*eda14cbcSMatt Macy void *zthr_arg; 224*eda14cbcSMatt Macy }; 225*eda14cbcSMatt Macy 226*eda14cbcSMatt Macy static void 227*eda14cbcSMatt Macy zthr_procedure(void *arg) 228*eda14cbcSMatt Macy { 229*eda14cbcSMatt Macy zthr_t *t = arg; 230*eda14cbcSMatt Macy 231*eda14cbcSMatt Macy mutex_enter(&t->zthr_state_lock); 232*eda14cbcSMatt Macy ASSERT3P(t->zthr_thread, ==, curthread); 233*eda14cbcSMatt Macy 234*eda14cbcSMatt Macy while (!t->zthr_cancel) { 235*eda14cbcSMatt Macy if (t->zthr_checkfunc(t->zthr_arg, t)) { 236*eda14cbcSMatt Macy mutex_exit(&t->zthr_state_lock); 237*eda14cbcSMatt Macy t->zthr_func(t->zthr_arg, t); 238*eda14cbcSMatt Macy mutex_enter(&t->zthr_state_lock); 239*eda14cbcSMatt Macy } else { 240*eda14cbcSMatt Macy /* 241*eda14cbcSMatt Macy * cv_wait_sig() is used instead of cv_wait() in 242*eda14cbcSMatt Macy * order to prevent this process from incorrectly 243*eda14cbcSMatt Macy * contributing to the system load average when idle. 244*eda14cbcSMatt Macy */ 245*eda14cbcSMatt Macy if (t->zthr_sleep_timeout == 0) { 246*eda14cbcSMatt Macy cv_wait_sig(&t->zthr_cv, &t->zthr_state_lock); 247*eda14cbcSMatt Macy } else { 248*eda14cbcSMatt Macy (void) cv_timedwait_sig_hires(&t->zthr_cv, 249*eda14cbcSMatt Macy &t->zthr_state_lock, t->zthr_sleep_timeout, 250*eda14cbcSMatt Macy MSEC2NSEC(1), 0); 251*eda14cbcSMatt Macy } 252*eda14cbcSMatt Macy } 253*eda14cbcSMatt Macy if (t->zthr_haswaiters) { 254*eda14cbcSMatt Macy t->zthr_haswaiters = B_FALSE; 255*eda14cbcSMatt Macy cv_broadcast(&t->zthr_wait_cv); 256*eda14cbcSMatt Macy } 257*eda14cbcSMatt Macy } 258*eda14cbcSMatt Macy 259*eda14cbcSMatt Macy /* 260*eda14cbcSMatt Macy * Clear out the kernel thread metadata and notify the 261*eda14cbcSMatt Macy * zthr_cancel() thread that we've stopped running. 262*eda14cbcSMatt Macy */ 263*eda14cbcSMatt Macy t->zthr_thread = NULL; 264*eda14cbcSMatt Macy t->zthr_cancel = B_FALSE; 265*eda14cbcSMatt Macy cv_broadcast(&t->zthr_cv); 266*eda14cbcSMatt Macy 267*eda14cbcSMatt Macy mutex_exit(&t->zthr_state_lock); 268*eda14cbcSMatt Macy thread_exit(); 269*eda14cbcSMatt Macy } 270*eda14cbcSMatt Macy 271*eda14cbcSMatt Macy zthr_t * 272*eda14cbcSMatt Macy zthr_create(const char *zthr_name, zthr_checkfunc_t *checkfunc, 273*eda14cbcSMatt Macy zthr_func_t *func, void *arg) 274*eda14cbcSMatt Macy { 275*eda14cbcSMatt Macy return (zthr_create_timer(zthr_name, checkfunc, 276*eda14cbcSMatt Macy func, arg, (hrtime_t)0)); 277*eda14cbcSMatt Macy } 278*eda14cbcSMatt Macy 279*eda14cbcSMatt Macy /* 280*eda14cbcSMatt Macy * Create a zthr with specified maximum sleep time. If the time 281*eda14cbcSMatt Macy * in sleeping state exceeds max_sleep, a wakeup(do the check and 282*eda14cbcSMatt Macy * start working if required) will be triggered. 283*eda14cbcSMatt Macy */ 284*eda14cbcSMatt Macy zthr_t * 285*eda14cbcSMatt Macy zthr_create_timer(const char *zthr_name, zthr_checkfunc_t *checkfunc, 286*eda14cbcSMatt Macy zthr_func_t *func, void *arg, hrtime_t max_sleep) 287*eda14cbcSMatt Macy { 288*eda14cbcSMatt Macy zthr_t *t = kmem_zalloc(sizeof (*t), KM_SLEEP); 289*eda14cbcSMatt Macy mutex_init(&t->zthr_state_lock, NULL, MUTEX_DEFAULT, NULL); 290*eda14cbcSMatt Macy mutex_init(&t->zthr_request_lock, NULL, MUTEX_DEFAULT, NULL); 291*eda14cbcSMatt Macy cv_init(&t->zthr_cv, NULL, CV_DEFAULT, NULL); 292*eda14cbcSMatt Macy cv_init(&t->zthr_wait_cv, NULL, CV_DEFAULT, NULL); 293*eda14cbcSMatt Macy 294*eda14cbcSMatt Macy mutex_enter(&t->zthr_state_lock); 295*eda14cbcSMatt Macy t->zthr_checkfunc = checkfunc; 296*eda14cbcSMatt Macy t->zthr_func = func; 297*eda14cbcSMatt Macy t->zthr_arg = arg; 298*eda14cbcSMatt Macy t->zthr_sleep_timeout = max_sleep; 299*eda14cbcSMatt Macy 300*eda14cbcSMatt Macy t->zthr_thread = thread_create_named(zthr_name, NULL, 0, 301*eda14cbcSMatt Macy zthr_procedure, t, 0, &p0, TS_RUN, minclsyspri); 302*eda14cbcSMatt Macy 303*eda14cbcSMatt Macy mutex_exit(&t->zthr_state_lock); 304*eda14cbcSMatt Macy 305*eda14cbcSMatt Macy return (t); 306*eda14cbcSMatt Macy } 307*eda14cbcSMatt Macy 308*eda14cbcSMatt Macy void 309*eda14cbcSMatt Macy zthr_destroy(zthr_t *t) 310*eda14cbcSMatt Macy { 311*eda14cbcSMatt Macy ASSERT(!MUTEX_HELD(&t->zthr_state_lock)); 312*eda14cbcSMatt Macy ASSERT(!MUTEX_HELD(&t->zthr_request_lock)); 313*eda14cbcSMatt Macy VERIFY3P(t->zthr_thread, ==, NULL); 314*eda14cbcSMatt Macy mutex_destroy(&t->zthr_request_lock); 315*eda14cbcSMatt Macy mutex_destroy(&t->zthr_state_lock); 316*eda14cbcSMatt Macy cv_destroy(&t->zthr_cv); 317*eda14cbcSMatt Macy cv_destroy(&t->zthr_wait_cv); 318*eda14cbcSMatt Macy kmem_free(t, sizeof (*t)); 319*eda14cbcSMatt Macy } 320*eda14cbcSMatt Macy 321*eda14cbcSMatt Macy /* 322*eda14cbcSMatt Macy * Wake up the zthr if it is sleeping. If the thread has been cancelled 323*eda14cbcSMatt Macy * or is in the process of being cancelled, this is a no-op. 324*eda14cbcSMatt Macy */ 325*eda14cbcSMatt Macy void 326*eda14cbcSMatt Macy zthr_wakeup(zthr_t *t) 327*eda14cbcSMatt Macy { 328*eda14cbcSMatt Macy mutex_enter(&t->zthr_state_lock); 329*eda14cbcSMatt Macy 330*eda14cbcSMatt Macy /* 331*eda14cbcSMatt Macy * There are 5 states that we can find the zthr when issuing 332*eda14cbcSMatt Macy * this broadcast: 333*eda14cbcSMatt Macy * 334*eda14cbcSMatt Macy * [1] The common case of the thread being asleep, at which 335*eda14cbcSMatt Macy * point the broadcast will wake it up. 336*eda14cbcSMatt Macy * [2] The thread has been cancelled. Waking up a cancelled 337*eda14cbcSMatt Macy * thread is a no-op. Any work that is still left to be 338*eda14cbcSMatt Macy * done should be handled the next time the thread is 339*eda14cbcSMatt Macy * resumed. 340*eda14cbcSMatt Macy * [3] The thread is doing work and is already up, so this 341*eda14cbcSMatt Macy * is basically a no-op. 342*eda14cbcSMatt Macy * [4] The thread was just created/resumed, in which case the 343*eda14cbcSMatt Macy * behavior is similar to [3]. 344*eda14cbcSMatt Macy * [5] The thread is in the middle of being cancelled, which 345*eda14cbcSMatt Macy * will be a no-op. 346*eda14cbcSMatt Macy */ 347*eda14cbcSMatt Macy cv_broadcast(&t->zthr_cv); 348*eda14cbcSMatt Macy 349*eda14cbcSMatt Macy mutex_exit(&t->zthr_state_lock); 350*eda14cbcSMatt Macy } 351*eda14cbcSMatt Macy 352*eda14cbcSMatt Macy /* 353*eda14cbcSMatt Macy * Sends a cancel request to the zthr and blocks until the zthr is 354*eda14cbcSMatt Macy * cancelled. If the zthr is not running (e.g. has been cancelled 355*eda14cbcSMatt Macy * already), this is a no-op. Note that this function should not be 356*eda14cbcSMatt Macy * called from syncing context as it could deadlock with the zthr_func. 357*eda14cbcSMatt Macy */ 358*eda14cbcSMatt Macy void 359*eda14cbcSMatt Macy zthr_cancel(zthr_t *t) 360*eda14cbcSMatt Macy { 361*eda14cbcSMatt Macy mutex_enter(&t->zthr_request_lock); 362*eda14cbcSMatt Macy mutex_enter(&t->zthr_state_lock); 363*eda14cbcSMatt Macy 364*eda14cbcSMatt Macy /* 365*eda14cbcSMatt Macy * Since we are holding the zthr_state_lock at this point 366*eda14cbcSMatt Macy * we can find the state in one of the following 4 states: 367*eda14cbcSMatt Macy * 368*eda14cbcSMatt Macy * [1] The thread has already been cancelled, therefore 369*eda14cbcSMatt Macy * there is nothing for us to do. 370*eda14cbcSMatt Macy * [2] The thread is sleeping so we set the flag, broadcast 371*eda14cbcSMatt Macy * the CV and wait for it to exit. 372*eda14cbcSMatt Macy * [3] The thread is doing work, in which case we just set 373*eda14cbcSMatt Macy * the flag and wait for it to finish. 374*eda14cbcSMatt Macy * [4] The thread was just created/resumed, in which case 375*eda14cbcSMatt Macy * the behavior is similar to [3]. 376*eda14cbcSMatt Macy * 377*eda14cbcSMatt Macy * Since requests are serialized, by the time that we get 378*eda14cbcSMatt Macy * control back we expect that the zthr is cancelled and 379*eda14cbcSMatt Macy * not running anymore. 380*eda14cbcSMatt Macy */ 381*eda14cbcSMatt Macy if (t->zthr_thread != NULL) { 382*eda14cbcSMatt Macy t->zthr_cancel = B_TRUE; 383*eda14cbcSMatt Macy 384*eda14cbcSMatt Macy /* broadcast in case the zthr is sleeping */ 385*eda14cbcSMatt Macy cv_broadcast(&t->zthr_cv); 386*eda14cbcSMatt Macy 387*eda14cbcSMatt Macy while (t->zthr_thread != NULL) 388*eda14cbcSMatt Macy cv_wait(&t->zthr_cv, &t->zthr_state_lock); 389*eda14cbcSMatt Macy 390*eda14cbcSMatt Macy ASSERT(!t->zthr_cancel); 391*eda14cbcSMatt Macy } 392*eda14cbcSMatt Macy 393*eda14cbcSMatt Macy mutex_exit(&t->zthr_state_lock); 394*eda14cbcSMatt Macy mutex_exit(&t->zthr_request_lock); 395*eda14cbcSMatt Macy } 396*eda14cbcSMatt Macy 397*eda14cbcSMatt Macy /* 398*eda14cbcSMatt Macy * Sends a resume request to the supplied zthr. If the zthr is already 399*eda14cbcSMatt Macy * running this is a no-op. Note that this function should not be 400*eda14cbcSMatt Macy * called from syncing context as it could deadlock with the zthr_func. 401*eda14cbcSMatt Macy */ 402*eda14cbcSMatt Macy void 403*eda14cbcSMatt Macy zthr_resume(zthr_t *t) 404*eda14cbcSMatt Macy { 405*eda14cbcSMatt Macy mutex_enter(&t->zthr_request_lock); 406*eda14cbcSMatt Macy mutex_enter(&t->zthr_state_lock); 407*eda14cbcSMatt Macy 408*eda14cbcSMatt Macy ASSERT3P(&t->zthr_checkfunc, !=, NULL); 409*eda14cbcSMatt Macy ASSERT3P(&t->zthr_func, !=, NULL); 410*eda14cbcSMatt Macy ASSERT(!t->zthr_cancel); 411*eda14cbcSMatt Macy ASSERT(!t->zthr_haswaiters); 412*eda14cbcSMatt Macy 413*eda14cbcSMatt Macy /* 414*eda14cbcSMatt Macy * There are 4 states that we find the zthr in at this point 415*eda14cbcSMatt Macy * given the locks that we hold: 416*eda14cbcSMatt Macy * 417*eda14cbcSMatt Macy * [1] The zthr was cancelled, so we spawn a new thread for 418*eda14cbcSMatt Macy * the zthr (common case). 419*eda14cbcSMatt Macy * [2] The zthr is running at which point this is a no-op. 420*eda14cbcSMatt Macy * [3] The zthr is sleeping at which point this is a no-op. 421*eda14cbcSMatt Macy * [4] The zthr was just spawned at which point this is a 422*eda14cbcSMatt Macy * no-op. 423*eda14cbcSMatt Macy */ 424*eda14cbcSMatt Macy if (t->zthr_thread == NULL) { 425*eda14cbcSMatt Macy t->zthr_thread = thread_create(NULL, 0, zthr_procedure, t, 426*eda14cbcSMatt Macy 0, &p0, TS_RUN, minclsyspri); 427*eda14cbcSMatt Macy } 428*eda14cbcSMatt Macy 429*eda14cbcSMatt Macy mutex_exit(&t->zthr_state_lock); 430*eda14cbcSMatt Macy mutex_exit(&t->zthr_request_lock); 431*eda14cbcSMatt Macy } 432*eda14cbcSMatt Macy 433*eda14cbcSMatt Macy /* 434*eda14cbcSMatt Macy * This function is intended to be used by the zthr itself 435*eda14cbcSMatt Macy * (specifically the zthr_func callback provided) to check 436*eda14cbcSMatt Macy * if another thread has signaled it to stop running before 437*eda14cbcSMatt Macy * doing some expensive operation. 438*eda14cbcSMatt Macy * 439*eda14cbcSMatt Macy * returns TRUE if we are in the middle of trying to cancel 440*eda14cbcSMatt Macy * this thread. 441*eda14cbcSMatt Macy * 442*eda14cbcSMatt Macy * returns FALSE otherwise. 443*eda14cbcSMatt Macy */ 444*eda14cbcSMatt Macy boolean_t 445*eda14cbcSMatt Macy zthr_iscancelled(zthr_t *t) 446*eda14cbcSMatt Macy { 447*eda14cbcSMatt Macy ASSERT3P(t->zthr_thread, ==, curthread); 448*eda14cbcSMatt Macy 449*eda14cbcSMatt Macy /* 450*eda14cbcSMatt Macy * The majority of the functions here grab zthr_request_lock 451*eda14cbcSMatt Macy * first and then zthr_state_lock. This function only grabs 452*eda14cbcSMatt Macy * the zthr_state_lock. That is because this function should 453*eda14cbcSMatt Macy * only be called from the zthr_func to check if someone has 454*eda14cbcSMatt Macy * issued a zthr_cancel() on the thread. If there is a zthr_cancel() 455*eda14cbcSMatt Macy * happening concurrently, attempting to grab the request lock 456*eda14cbcSMatt Macy * here would result in a deadlock. 457*eda14cbcSMatt Macy * 458*eda14cbcSMatt Macy * By grabbing only the zthr_state_lock this function is allowed 459*eda14cbcSMatt Macy * to run concurrently with a zthr_cancel() request. 460*eda14cbcSMatt Macy */ 461*eda14cbcSMatt Macy mutex_enter(&t->zthr_state_lock); 462*eda14cbcSMatt Macy boolean_t cancelled = t->zthr_cancel; 463*eda14cbcSMatt Macy mutex_exit(&t->zthr_state_lock); 464*eda14cbcSMatt Macy return (cancelled); 465*eda14cbcSMatt Macy } 466*eda14cbcSMatt Macy 467*eda14cbcSMatt Macy /* 468*eda14cbcSMatt Macy * Wait for the zthr to finish its current function. Similar to 469*eda14cbcSMatt Macy * zthr_iscancelled, you can use zthr_has_waiters to have the zthr_func end 470*eda14cbcSMatt Macy * early. Unlike zthr_cancel, the thread is not destroyed. If the zthr was 471*eda14cbcSMatt Macy * sleeping or cancelled, return immediately. 472*eda14cbcSMatt Macy */ 473*eda14cbcSMatt Macy void 474*eda14cbcSMatt Macy zthr_wait_cycle_done(zthr_t *t) 475*eda14cbcSMatt Macy { 476*eda14cbcSMatt Macy mutex_enter(&t->zthr_state_lock); 477*eda14cbcSMatt Macy 478*eda14cbcSMatt Macy /* 479*eda14cbcSMatt Macy * Since we are holding the zthr_state_lock at this point 480*eda14cbcSMatt Macy * we can find the state in one of the following 5 states: 481*eda14cbcSMatt Macy * 482*eda14cbcSMatt Macy * [1] The thread has already cancelled, therefore 483*eda14cbcSMatt Macy * there is nothing for us to do. 484*eda14cbcSMatt Macy * [2] The thread is sleeping so we set the flag, broadcast 485*eda14cbcSMatt Macy * the CV and wait for it to exit. 486*eda14cbcSMatt Macy * [3] The thread is doing work, in which case we just set 487*eda14cbcSMatt Macy * the flag and wait for it to finish. 488*eda14cbcSMatt Macy * [4] The thread was just created/resumed, in which case 489*eda14cbcSMatt Macy * the behavior is similar to [3]. 490*eda14cbcSMatt Macy * [5] The thread is the middle of being cancelled, which is 491*eda14cbcSMatt Macy * similar to [3]. We'll wait for the cancel, which is 492*eda14cbcSMatt Macy * waiting for the zthr func. 493*eda14cbcSMatt Macy * 494*eda14cbcSMatt Macy * Since requests are serialized, by the time that we get 495*eda14cbcSMatt Macy * control back we expect that the zthr has completed it's 496*eda14cbcSMatt Macy * zthr_func. 497*eda14cbcSMatt Macy */ 498*eda14cbcSMatt Macy if (t->zthr_thread != NULL) { 499*eda14cbcSMatt Macy t->zthr_haswaiters = B_TRUE; 500*eda14cbcSMatt Macy 501*eda14cbcSMatt Macy /* broadcast in case the zthr is sleeping */ 502*eda14cbcSMatt Macy cv_broadcast(&t->zthr_cv); 503*eda14cbcSMatt Macy 504*eda14cbcSMatt Macy while ((t->zthr_haswaiters) && (t->zthr_thread != NULL)) 505*eda14cbcSMatt Macy cv_wait(&t->zthr_wait_cv, &t->zthr_state_lock); 506*eda14cbcSMatt Macy 507*eda14cbcSMatt Macy ASSERT(!t->zthr_haswaiters); 508*eda14cbcSMatt Macy } 509*eda14cbcSMatt Macy 510*eda14cbcSMatt Macy mutex_exit(&t->zthr_state_lock); 511*eda14cbcSMatt Macy } 512*eda14cbcSMatt Macy 513*eda14cbcSMatt Macy /* 514*eda14cbcSMatt Macy * This function is intended to be used by the zthr itself 515*eda14cbcSMatt Macy * to check if another thread is waiting on it to finish 516*eda14cbcSMatt Macy * 517*eda14cbcSMatt Macy * returns TRUE if we have been asked to finish. 518*eda14cbcSMatt Macy * 519*eda14cbcSMatt Macy * returns FALSE otherwise. 520*eda14cbcSMatt Macy */ 521*eda14cbcSMatt Macy boolean_t 522*eda14cbcSMatt Macy zthr_has_waiters(zthr_t *t) 523*eda14cbcSMatt Macy { 524*eda14cbcSMatt Macy ASSERT3P(t->zthr_thread, ==, curthread); 525*eda14cbcSMatt Macy 526*eda14cbcSMatt Macy mutex_enter(&t->zthr_state_lock); 527*eda14cbcSMatt Macy 528*eda14cbcSMatt Macy /* 529*eda14cbcSMatt Macy * Similarly to zthr_iscancelled(), we only grab the 530*eda14cbcSMatt Macy * zthr_state_lock so that the zthr itself can use this 531*eda14cbcSMatt Macy * to check for the request. 532*eda14cbcSMatt Macy */ 533*eda14cbcSMatt Macy boolean_t has_waiters = t->zthr_haswaiters; 534*eda14cbcSMatt Macy mutex_exit(&t->zthr_state_lock); 535*eda14cbcSMatt Macy return (has_waiters); 536*eda14cbcSMatt Macy } 537