> Date: Thu, 26 Jul 2018 22:57:57 -0700 > From: Phil Nelson <p...@netbsd.org> > > I'm trying to work with workqueues and am having a locking problem
Is this a conceptual problem, or do you have a symptom that you're actually hitting with specific code? If the latter, can you describe the symptom and quote the code? > Lets say I have a function f() as follows: > > int f() { > mutex_enter(&some_mutex); > ...... code ..... > mutex_exit(&some_mutex); > } > > and now lets say that I start another function running via a workqueue, g() > g() { > ..... some code .... > if (f()) { > .... do something else ... > } else { > error > } > } > > So, my question is: if g() is running f() and holds the mutex and then the > main code calls f() ... will this be detected as already holding the lock? > > If it will be detected as already holding the lock, how can I do locking > between the code that does the enqueue and the code in the work item? The workqueue function runs asynchronously in its own thread. You are allowed to hold a lock when scheduling work with workqueue_enqueue that the workqueue function itself will acquire too. Indeed, many users will do exactly that. Note that in your example, the caller of f must not hold some_mutex, workqueues or not. If g _already_ holds the mutex when it calls f, that's a bug. Here's how you can use a workqueue to schedule work if it's not already scheduled: struct foo_softc { ... struct workqueue *sc_wq; kmutex_t sc_work_lock; struct work sc_work; bool sc_work_scheduled; ... }; static void do_work(struct work *wk, void *arg) { struct foo_softc *sc = container_of(wk, struct foo_softc, sc_work); mutex_enter(&sc->sc_work_lock); sc->sc_work_scheduled = false; mutex_exit(&sc->sc_work_lock); /* do stuff */ } static void foo_intr(...) { ... mutex_enter(&sc->sc_work_lock); if (!sc->sc_work_scheduled) { workqueue_enqueue(sc->sc_wq, &sc->sc_work, NULL); sc->sc_work_scheduled = true; } mutex_exit(&sc->sc_work_lock); ... }