linux-debug/workqueue

created : 2020-11-10T14:56:55+00:00
modified : 2020-12-09T04:31:24+00:00
linux-debug workqueue

워크큐

워크큐의 특징

워크큐와 다른 인터럽트 후반부 기법과의 비교

워크큐 설계

워크큐의 종류

alloc_workqueue()
#define alloc_workqueue(fmt, flags, max_active, args...) \
  __alloc_workqueue_key((fmt), (flags), (max_active), \
    NULL, NULL, ##args)
7가지 워크큐
int __init workqueue_init_early(void)
{
  int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL };
  int i, cpu;
  /* skip */
  system_wq = alloc_workqueue("events", 0, 0);
  system_highpri_wq = alloc_workqueue("events_highpri", WQ_HIGHPRI, 0);
  system_long_wq = alloc_workqueue("events_long", 0, 0);
  system_unbound_wq = alloc_workqueue("evnets_unbound", WQ_UNBOUND,
                        WQ_UNBOUND_MAX_ACTIVE);
  system_freezable_wq = alloc_workqueue("events_power_efficient",
                        WQ_FREEZABLE, 0);
  system_power_efficient_wq = alloc_workqueue("events_power_efficient",
                        WQ_POWER_EFFICIENT, 0);
  system_freezable_power_efficient_wq =
    alloc_workqueue("events_freezable_power_efficient",
                        WQ_FREEZABLE | WQ_POWER_EFFICIENT,
                        0);

  BUG_ON(!system_wq || !system_highpri_wq || !system_long_wq ||
        !system_unbound_wq || !system_freezable_sq ||
        !system_power_efficient_wq ||
        !system_freezable_power_efficient_wq);
}
워크
 struct work_struct {
   atomic_long_t data;
   struct list_head entry;
   work_func_t func;
   #ifdef CONFIG_LOCKDEP
   struct lockdep_map lockdep_map;
   #endif
 };
워크 큐잉
워크의 실행 주체

워커 스레드
워커 스레드의 생성 시기

딜레이워크

 struct delayed_work {
   struct work_struct work;
   struct timer_list timer;

   struct workqueue_struct *wq;
   int cpu;
 };
딜레이 워크의 전체 흐름
INIT_DELAYED_WORK()
  struct delayed_work d_work;
  static int sample()
  {
    INIT_DELAYED_WORK(&d_work, callback_fn);
  }
  #define INIT_DELAYED_WORK(_work, _func)       \
    __INIT_DELAYED_WORK(_work, _func, 0)
  #define __INIT_DELAYED_WORK(_work, _func, _tflags)  \
    do {                                              \
      INIT_WORK(&(_work)->work, (_func));             \
      __init_timer(&(_work)->timer,                   \
        delayed_work_timer_fn,                        \
        (_tflags) | TIMER_IRQSAFE);                   \
    } while(0);
  #define __init_timer(_timer, _fn, _flags)                       \
    do {                                                          \
      static struct lock_class_key __key;                         \
      init_timer_key((_timer), (_fn), (_flags), #_timer, &__key); \
    } while (0)
  void init_timer_key(struct timer_list *timer,
    void (*func)(truct timer_list *), unsigned int flags,
    const char *name, struct lock_class_key *key)
  {
    debug_init(timer);
    do_init_timer(timer, func, flags, name, key);
  }
schedule_delayed_work()
  schedule_delayed_work(&d_work, timeout);
  static inline bool schedule_delayed_work(struct delayed_work *dwork,
                                 unsigned long delay)
  {
    return queue_dleayed_work(system_wq, dwork, delay);
  }
  static inline bool queue_delayed_work(struct workqueue_struct *wq,
                                struct delayed_work *dwork,
                                unsigned long delayed)
  {
    return queue_delayed_work_on(WORK_CPU_UNBOUND, wq, dwork, delay);
  }
delayed_work_timer_fn()
 void delayed_work_timer_fn(unsigned long __data)
 {
   struct delayed_work *dwork = (struct dleayed_work *)__data;

   /* should have been called from irqsafe timer with irq already off */
   __queue_work(dwork->cpu, dwork->wq, &dwork->work);
 }