Linux--workqueue之初始化

    技术2022-07-12  76

    1:初始化第一步:分配各项数据结构及系统workqueue /**

    workqueue_init_early - early init for workqueue subsystem

    This is the first half of two-staged workqueue subsystem initialization

    and invoked as soon as the bare basics - memory allocation, cpumasks and

    idr are up. It sets up all the data structures and system workqueues

    and allows early boot code to create workqueues and queue/cancel work

    items. Actual work item execution starts only after kthreads can be

    created and scheduled right before early initcalls. / int __init workqueue_init_early(void) / initialize CPU pools / for_each_possible_cpu(cpu) //每个cpu for_each_cpu_worker_pool(pool, cpu) //每个cpu的worker_pool init_worker_pool(pool) … pool->flags |= POOL_DISASSOCIATED; //worker_pool未链接标记 … pool->refcnt = 1; / shouldn’t fail above this point */ pool->attrs = alloc_workqueue_attrs(GFP_KERNEL);

    pool->cpu = cpu; cpumask_copy(pool->attrs->cpumask, cpumask_of(cpu)); pool->attrs->nice = std_nice[i++]; pool->node = cpu_to_node(cpu); worker_pool_assign_id(pool) ret = idr_alloc(&worker_pool_idr, pool, 0, WORK_OFFQ_POOL_NONE, GFP_KERNEL); pool->id = ret

    /* create default unbound and ordered wq attrs */ for (i = 0; i < NR_STD_WORKER_POOLS; i++) //system中各有2个,分普通级和优先级 attrs = alloc_workqueue_attrs(GFP_KERNEL) attrs->nice = std_nice[i]; unbound_std_wq_attrs[i] = attrs;

    /* * An ordered wq should have only one pwq as ordering is * guaranteed by max_active which is enforced by pwqs. * Turn off NUMA so that dfl_pwq is used for all nodes. */ BUG_ON(!(attrs = alloc_workqueue_attrs(GFP_KERNEL))); attrs->nice = std_nice[i]; attrs->no_numa = true; ordered_wq_attrs[i] = attrs;

    //根据不同的传参(flag, max_active),分配7种系统workqueue(参考"workqueue.h"),以普通workqueue为例 system_wq = alloc_workqueue(“events”, 0, 0); __alloc_workqueue_key((fmt), (flags), (max_active), NULL, NULL, ##args) … wq = kzalloc(sizeof(*wq) + tbl_size, GFP_KERNEL); //为workqueque_struct分配内存空间 vsnprintf(wq->name, sizeof(wq->name), fmt, args) //指定workqueque_struct指定name max_active = max_active ?: WQ_DFL_ACTIVE; //如果传参为0,用经验默认值256 wq->flags = flags; wq->saved_max_active = max_active; … alloc_and_link_pwqs(wq) wq->cpu_pwqs = alloc_percpu(struct pool_workqueue); //每个cpu分配一个pool_workqueue空间 for_each_possible_cpu(cpu) struct pool_workqueue *pwq = per_cpu_ptr(wq->cpu_pwqs, cpu); //指向本cpu的pwq struct worker_pool *cpu_pools = per_cpu(cpu_worker_pools, cpu); //指向本cpu的worker_pools

    /* initialize newly alloced @pwq which is associated with @wq and @pool */ init_pwq(pwq, wq, &cpu_pools[highpri]); memset(pwq, 0, sizeof(*pwq)); pwq->pool = pool; //关联的worker_pool pwq->wq = wq; //所属的workqueue_struct pwq->flush_color = -1; pwq->refcnt = 1; INIT_LIST_HEAD(&pwq->delayed_works); //处于延时状态的work链表 INIT_LIST_HEAD(&pwq->pwqs_node); //pwq组成的链表 INIT_LIST_HEAD(&pwq->mayday_node); INIT_WORK(&pwq->unbound_release_work, pwq_unbound_release_workfn); /* sync @pwq with the current state of its associated wq and link it */ link_pwq(pwq); /* sync max_active to the current setting */ pwq_adjust_max_active(pwq); //!freezable, quite; /* link in @pwq */ list_add_rcu(&pwq->pwqs_node, &wq->pwqs); //将这个pwq插入到wq的pwqs链表头 for_each_pwq(pwq, wq) pwq_adjust_max_active(pwq); pwq->max_active = wq->saved_max_active; while (!list_empty(&pwq->delayed_works) && pwq->nr_active < pwq->max_active) pwq_activate_first_delayed(pwq); struct work_struct *work = list_first_entry(&pwq->delayed_works, struct work_struct, entry); pwq_activate_delayed_work(work); struct pool_workqueue *pwq = get_work_pwq(work); trace_workqueue_activate_work(work); if (list_empty(&pwq->pool->worklist)) pwq->pool->watchdog_ts = jiffies; move_linked_works(work, &pwq->pool->worklist, NULL); /* * Linked worklist will always end before the end of the list, * use NULL for list head. */ list_for_each_entry_safe_from(work, n, NULL, entry) { //从pwq->delayed_works移除work,并加入到pwq->pool->worklist中, //如果WORK_STRUCT_LINKED没有置位,只移一个。 list_move_tail(&work->entry, head); if (!(*work_data_bits(work) & WORK_STRUCT_LINKED)) break; } __clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work)); pwq->nr_active++; /* * Need to kick a worker after thawed or an unbound wq's * max_active is bumped. It's a slow path. Do it always. */ wake_up_worker(pwq->pool); //唤醒worker_pool中的第一个idle worker, 初始化阶段还没有 list_add_tail_rcu(&wq->list, &workqueues); //将workqueue_struct加入到workqueues全局链表中

    2:初始化第二步: 初始化worker_pool, worker /**

    workqueue_init - bring workqueue subsystem fully online

    This is the latter half of two-staged workqueue subsystem initialization

    and invoked as soon as kthreads can be created and scheduled.

    Workqueues have been created and work items queued on them, but there

    are no kworkers executing the work items yet. Populate the worker pools

    with the initial workers and enable future kworker creations. */ int __init workqueue_init(void) //根据绑定的cpu,为worker_pool创建node ID for_each_possible_cpu(cpu) { for_each_cpu_worker_pool(pool, cpu) { pool->node = cpu_to_node(cpu); } }

    //为系统中需要创建rescuer worker的workqueue_struct执行创建,并唤醒该worker->task list_for_each_entry(wq, &workqueues, list) { wq_update_unbound_numa(wq, smp_processor_id(), true); WARN(init_rescuer(wq), “workqueue: failed to create early rescuer for %s”, wq->name); } /* * Workqueues which may be used during memory reclaim should have a rescuer * to guarantee forward progress. */ static int init_rescuer(struct workqueue_struct *wq) rescuer = alloc_worker(NUMA_NO_NODE); rescuer->rescue_wq = wq; rescuer->task = kthread_create(rescuer_thread, rescuer, “%s”, wq->name); wq->rescuer = rescuer; kthread_bind_mask(rescuer->task, cpu_possible_mask); wake_up_process(rescuer->task);

    /* create the initial workers */ for_each_online_cpu(cpu) { //为每个online cpu, 1:POOL_DISASSOCIATED标记清0; 2:创建worker并唤醒task for_each_cpu_worker_pool(pool, cpu) { pool->flags &= ~POOL_DISASSOCIATED; BUG_ON(!create_worker(pool)); } }

    //为每个unbound_pool_hash,创建worker并唤醒task hash_for_each(unbound_pool_hash, bkt, pool, hash_node) BUG_ON(!create_worker(pool)); worker->task = kthread_create_on_node(worker_thread, worker, pool->node, “kworker/%s”, id_buf); worker->pool->nr_workers++; worker_enter_idle(worker); wake_up_process(worker->task);

    wq_online = true; wq_watchdog_init(); //初始化workqueue的watchdog

    Processed: 0.010, SQL: 9