2013-02-19 1 views
5

Sto usando la workqueue condivisa del kernel e ho una struttura delayed_work che voglio riprogrammare per essere eseguita immediatamente.Cosa succede quando il kernel delayed_work è riprogrammato

Il seguente codice garantisce che il delayed_work verrà eseguito il prima possibile?

cancel_delayed_work(work); 
schedule_delayed_work(work, 0); 

Cosa succede in una situazione in cui il lavoro è già in esecuzione? cancel_delayed_work restituirà 0, ma non sono sicuro di cosa farà schedule_delayed_work se il lavoro è attualmente in esecuzione o non è pianificato.

+0

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. –

risposta

4

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.