Linux Transfer Parameter for Function in Declare_Work

Linux transfer parameter for function in DECLARE_WORK

DECLARE_WORK is primarily for static work items, where no instance data is needed. You want INIT_WORK. Use this to initialize a work_struct that is a member of another structure (of your choosing), then use container_of in the callback to get the pointer to the containing structure. This container_of pattern is extremely common in the Linux kernel, so it's a good idea to get familiar with it!

You can see an example of this with wl1271_netstack_work - take a look at the initialization point and the callback.

When should I provide #defined macro for declaring or initializing variable in Linux Kernel?

I think it is a bit of both.

#define __WORK_INITIALIZER(n, f) {                  \
.data = WORK_DATA_STATIC_INIT(), \
.entry = { &(n).entry, &(n).entry }, \
.func = (f), \
__WORK_INIT_LOCKDEP_MAP(#n, &(n)) \
}

#define DECLARE_WORK(n, f) \
struct work_struct n = __WORK_INITIALIZER(n, f)

First of all, in this case, it is most probably due to the simple reason that initializing work_struct is at least 4-5 lines of code and since this is something that happens quite a lot in the kernel, it would add unnecessary verbosity to the code, so it has been abstracted into a macro. It could have been a function, but that is also less efficient.

Also, it is difficult for kernel developers and maintainers, when reviewing the code, to ensure that every time a work_struct is declared, it is also initialized properly. In this case, since the initialization code is at a single place, they can safely assume that any code that uses this macro will have initialized the struct properly.

Thirdly, you may be a developer working on some specific driver inside a specific subsystem and may not want to know the internals of the kernel work_queue mechanism. You just want to be able to queue your work using the api provided. This macro also saves you from being bothered about the internals. Even if a new field is added to the struct tomorrow for internal use, your driver code does not need to change.

How to offload NAPI poll function to workqueue

  1. How do I pass the NAPI poll function arguments to the work_struct?

Just create new structure, which embed work_struct and add your arguments into it:

struct my_work {
struct work_struct base_work;// Embedded work_struct
struct napi_struct *napi; // Your arguments
int budget;
};

static int smsc911x_poll(struct napi_struct *napi, int budget) {
struct my_work* p = kmalloc(sizeof(*p), GFP_ATOMIC /* Flag usable for interrupt context */);
INIT_WORK(&p->base_work, smsc911x_poll_work); // Initialize underliying structure.
p->budget = budget; // Initialize your members
p->napi = napi;
...
}

  1. How do I get the NAPI poll function arguments back from the work_struct? (related to Q.1 above)

Use container_of:

static int smsc911x_poll_work(struct work_struct *work) {
struct my_work* p = container_of(work, struct my_work, base_work);
...
}

  1. How can I return the npackets value to the original NAPI poll function caller?

As I understand from description(see, e.g., http://www.linuxfoundation.org/collaborate/workgroups/networking/napi) this function should process packets which are ready. And this processing should be done within function itself, without deferring to workqueue or similar.

How to use Linux Work Queue

If you want to pass data to your work queue function, just embed the work_struct structure inside your own data structure and use container_of inside your work function to retrieve it.

As for a simple example, the kernel is full of it - just git grep work_struct. You can look at drivers/cpufreq/cpufreq.c (handle_update function) for a simple example. The article below also embeds an example at the end, but it does not use container_of and instead relies on the fact that the first member of a structure has the same address as its parent:

http://www.ibm.com/developerworks/linux/library/l-tasklets/index.html

How to play the YOUTUBE video automatically when a page loads using PHP

There's the autoplay parameter. Just append it to the urls in the src attribute and the movie parameter.



Related Topics



Leave a reply



Submit