Bene, sapete cosa dicono della necessità di essere madre di ogni invenzione (o ricerca in questo caso). Avevo davvero bisogno di questa risposta e l'ho ottenuta scavando attraverso il kernel/workqueue.c. Sebbene la risposta sia per lo più contenuta nel doc comments combinato con Documentation/workqueue.txt
, non è chiaramente indicata senza leggere l'intera specifica sul sottosistema Concurrency Managed Workqueue (cmwq) e anche in questo caso, alcune informazioni non sono aggiornate!
Risposta breve
Will [il codice] garanzia che il delayed_work verrà eseguito il prima possibile?
Sì (con l'avvertenza di seguito)
Cosa succede in una situazione in cui il lavoro è già in esecuzione?
Verrà eseguito un certo punto dopo i attualmente in esecuzione delayed_work
funzione termina e sulla stessa CPU come l'ultimo, anche se qualsiasi altro lavoro già accodato che WorkQueue (o lavoro ritardato che è dovuto) sarà corri prima Si presume che non sia stato nuovamente inizializzato l'oggetto delayed_work
o work_struct
e che non sia stato modificato il puntatore di pubblicazione work->func
.
lungo risposta
Quindi, prima di tutto, struct delayed_work
utilizza pseudo-eredità derivare da struct work_struct
grazie all'integrazione di un struct work_struct
come il suo primo membro. Questo sottosistema utilizza alcuni incredibili bit atomici per avere una certa concorrenza. Un work_struct
è "di proprietà" quando è il campo data
ha il bit WORK_STRUCT_PENDING
impostato. Quando un lavoratore esegue il tuo lavoro, è releases ownership e registra l'ultimo pool di lavoro tramite la funzione privata set_work_pool_and_clear_pending() - questa è l'ultima volta che l'API modifica l'oggetto work_struct
(fino a quando non lo si pianifica nuovamente, ovviamente). Chiamare il numero cancel_delayed_work()
fa esattamente la stessa cosa.
Quindi se si chiama cancel_delayed_work()
quando la funzione di lavoro ha già iniziato l'esecuzione, restituisce false
(come pubblicizzato) poiché non è più di proprietà di nessuno, anche se potrebbe essere ancora in esecuzione. Tuttavia, quando provi a re-aggiungerlo con schedule_delayed_work()
, sarà examine the work per scoprire l'ultimo pool_workqueue
e poi scoprire se qualcuno di quegli operai di pool_workqueue
sta attualmente eseguendo il tuo lavoro.Se lo sono (e non hai cambiato il puntatore work->func
), esso aggiunge semplicemente il lavoro alla coda di quello pool_workqueue
ed è così che evita il re-entrancy! Altrimenti, lo accoderà sul pool per la CPU corrente. (Il motivo per il controllo work->func
puntatore è quello di consentire il riutilizzo degli oggetti work_struct
.)
Nota, tuttavia, che semplicemente chiamando schedule_delayed_work()
senza cancellarla prima si tradurrà in non cambiamento se il lavoro è ancora in coda, quindi è sicuramente deve prima cancellarlo
EDIT: Oh sì, se sei confuso dalla discussione in Documentation/workqueue.txt
su WQ_NON_REENTRANT
, ignoralo. Questo flag è deprecato e ignorato e tutte le sequenze di lavoro sono ora non rientranti.
uugh! Questo è il mio attuale dilemma. In effetti, uno dei backtrace che avevo in oops indicava che potrebbe essere rientrato dopo aver fatto il tuo codice esatto sopra. Ho aggiunto un contatore atomico per prevenirlo, ma ho bisogno di conoscere il modo corretto di riprogrammare anche delayed_work. –