2013-02-19 12 views
5

Używam wspólnego pliku roboczego jądra, a ja mam strukturę delayed_work, którą chcę przełożyć, aby działał od razu.Co się stanie, gdy jądro delayed_work zostanie zmienione na

Czy poniższy kod gwarantuje, że delayed_work będzie działać tak szybko, jak to możliwe?

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

Co dzieje się w sytuacji, gdy praca jest już uruchomiona? cancel_delayed_work zwróci 0, ale nie jestem pewien, co zrobi schedule_delayed_work, jeśli praca jest obecnie uruchomiona lub jest nieplanowana.

+0

uugh! To jest mój obecny dylemat. W rzeczywistości jeden z zapisów śledzenia, które miałem w oops, wskazał, że mógł on ponownie wejść po wykonaniu twojego kodu powyżej. Dodałem licznik atomowy, aby temu zapobiec, ale muszę również znać poprawny sposób na zmianę terminu delayed_work. –

Odpowiedz

4

Cóż, wiesz, co mówią o konieczności bycia matką wszystkich wynalazków (lub badań w tym przypadku). Naprawdę potrzebowałem tej odpowiedzi i otrzymałem ją, przeglądając jądro/workqueue.c. Chociaż odpowiedź jest głównie zawarta w doc comments w połączeniu z Documentation/workqueue.txt, nie jest to jasno napisane bez przeczytania całej specyfikacji podsystemu Współrzędna robocza z zarządzaniem współbieżnym (cmwq) i nawet wtedy niektóre informacje są nieaktualne!

Krótka odpowiedź

Will [kod] gwarantuje, że delayed_work będzie działać tak szybko, jak to możliwe?

Tak (z zastrzeżeniem poniżej)

Co się dzieje w sytuacji, gdy praca jest już uruchomiony?

Będzie on prowadzony w pewnym momencie po aktualnie uruchomione delayed_work wyjść funkcyjnych i na tym samym CPU jako ostatni, chociaż każda inna praca już w kolejce na tym workqueue (lub opóźnionego pracy, który jest należny) będzie być pierwszym na mecie. Zakłada się, że nie zainicjowano ponownie obiektu delayed_work lub work_struct i że nie zmieniono wskaźnika wartości work->func.

długa odpowiedź

Więc najpierw, struct delayed_work używa pseudo-dziedziczenie czerpać z struct work_struct przez osadzanie struct work_struct jako jej pierwszy człon. Ten podsystem używa jakiegoś niesamowitego atomowego sprzężenia bitów, by mieć poważną współbieżność. A work_struct jest "własnością", gdy ma ono ustawiony bit data. Kiedy robotnik wykonuje twoją pracę, to releases ownership i rejestruje ostatnią pulę roboczą za pomocą prywatnej funkcji set_work_pool_and_clear_pending() - jest to ostatni czas, gdy API modyfikuje obiekt work_struct (aż do czasu ponownego jego zaplanowania, oczywiście). Wywołanie cancel_delayed_work() wykonuje dokładnie to samo.

Więc jeśli zadzwonisz pod numer cancel_delayed_work(), gdy twoja funkcja robocza już się zaczęła, zwróci false (zgodnie z reklamą), ponieważ nie jest już własnością nikogo, nawet jeśli nadal może być uruchomiona. Jednak przy próbie ponownego dodania go za pomocą schedule_delayed_work(), będzie examine the work, aby odkryć ostatnie pool_workqueue, a następnie dowiedzieć się, czy któryś z tych pracowników pool_workqueue pracuje obecnie.Jeśli są (i nie zmieniłeś wskaźnika work->func), to po prostu dołączają pracę do kolejki tego pool_workqueue i to w ten sposób unika ponownego entrancy! W przeciwnym razie spowoduje umieszczenie go w kolejce do bieżącego procesora. (Powodem kontroli work->func wskaźnik jest umożliwienie ponownego wykorzystania obiektu work_struct.)

jednak pamiętać, że po prostu dzwoniąc schedule_delayed_work() bez anulowania najpierw spowoduje nie zmianę czy praca jest nadal w kolejce, więc na pewno musi najpierw anulować.

EDYCJA: O tak, jeśli jesteś zdezorientowany przez dyskusję w Documentation/workqueue.txt o WQ_NON_REENTRANT, zignoruj ​​to. Ta flaga jest uznawana za przestarzałą i ignorowana, a wszystkie paski robocze są teraz nieresetujące.

Powiązane problemy