Linux Kernel Architecture

(Jacob Rumans) #1

Chapter 14: Kernel Activities


Why does the kernel useatomic_long_tas the data type for a pointer to some arbitrary data, and not
void *as usual? In fact, former kernel versions definedwork_structas follows:

<workqueue.h>
struct work_struct {
...
void (*func)(void *);
void *data;
...
};

datawas represented by a pointer as expected. However, the kernel does use a little trick — which is
fairlyontheedgeofbeingdirty—tosqueezemoreinformation into the structure without spending
more memory. Because pointers are aligned on 4-byte boundaries on all supported architectures, the first
2 bits are guaranteed to be zero. They are therefore abused to contain flag bits. The remaining bits hold
the pointer information as usual. The following macros allow masking out the flag bits:

<workqueue.h>
#define WORK_STRUCT_FLAG_MASK (3UL)
#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)

Currently only a single flag is defined:WORK_STRUCT_PENDINGallows for finding out whether a delayable
work item is currently pending (if the bit is set) or not. The auxiliary macrowork_pending(work)allows
for checking for the bit. Note that the atomic data type ofdataensures that the bit can be modified
without concurrency problems.

To simplify declaring and filling a static instanceof this structure, the kernel provides the
INIT_WORK(work, func)macro, which supplies an existing instance ofwork_structwith a delayed
function. If a data argument is required, it must be set afterward.

There are two ways of adding awork_queueinstance to a work queue —queue_workand
queue_work_delayed. The first alternative has the following prototype:

kernel/workqueue.c
int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work)

It addsworkto the work queuewq; the work itself is performed at an undefined time (when the scheduler
selects the daemon).

To ensure that work queued will be executedaftera specified time interval has passed since submission,
thework_structneeds to be extended with a timer. The solution is as obvious as can be:

<workqueue.h>
struct delayed_work {
struct work_struct work;
struct timer_list timer;
};

queue_delayed_workis used to submit instances ofdelayed_workto a work queue. It ensure thatat least
one time interval specified (in jiffies) bydelayelapses before the deferred work is performed.
Free download pdf