Skip to content

Commit

Permalink
WorkStruct: Separate delayable and non-delayable events.
Browse files Browse the repository at this point in the history
Separate delayable work items from non-delayable work items be splitting them
into a separate structure (delayed_work), which incorporates a work_struct and
the timer_list removed from work_struct.

The work_struct struct is huge, and this limits it's usefulness.  On a 64-bit
architecture it's nearly 100 bytes in size.  This reduces that by half for the
non-delayable type of event.

Signed-Off-By: David Howells <dhowells@redhat.com>
  • Loading branch information
David Howells committed Nov 22, 2006
1 parent 0f9005a commit 52bad64
Show file tree
Hide file tree
Showing 22 changed files with 96 additions and 73 deletions.
2 changes: 1 addition & 1 deletion arch/x86_64/kernel/mce.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ void mce_log_therm_throt_event(unsigned int cpu, __u64 status)

static int check_interval = 5 * 60; /* 5 minutes */
static void mcheck_timer(void *data);
static DECLARE_WORK(mcheck_work, mcheck_timer, NULL);
static DECLARE_DELAYED_WORK(mcheck_work, mcheck_timer, NULL);

static void mcheck_check_cpu(void *info)
{
Expand Down
11 changes: 4 additions & 7 deletions drivers/ata/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -937,12 +937,9 @@ void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK)
return;

PREPARE_WORK(&ap->port_task, fn, data);
PREPARE_DELAYED_WORK(&ap->port_task, fn, data);

if (!delay)
rc = queue_work(ata_wq, &ap->port_task);
else
rc = queue_delayed_work(ata_wq, &ap->port_task, delay);
rc = queue_delayed_work(ata_wq, &ap->port_task, delay);

/* rc == 0 means that another user is using port task */
WARN_ON(rc == 0);
Expand Down Expand Up @@ -5320,8 +5317,8 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
#endif

INIT_WORK(&ap->port_task, NULL, NULL);
INIT_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap);
INIT_DELAYED_WORK(&ap->port_task, NULL, NULL);
INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap);
INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan, ap);
INIT_LIST_HEAD(&ap->eh_done_q);
init_waitqueue_head(&ap->eh_wait_q);
Expand Down
2 changes: 1 addition & 1 deletion drivers/ata/libata-eh.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ void ata_scsi_error(struct Scsi_Host *host)
if (ap->pflags & ATA_PFLAG_LOADING)
ap->pflags &= ~ATA_PFLAG_LOADING;
else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
queue_work(ata_aux_wq, &ap->hotplug_task);
queue_delayed_work(ata_aux_wq, &ap->hotplug_task, 0);

if (ap->pflags & ATA_PFLAG_RECOVERED)
ata_port_printk(ap, KERN_INFO, "EH complete\n");
Expand Down
2 changes: 1 addition & 1 deletion drivers/char/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -1424,7 +1424,7 @@ static unsigned int ip_cnt;

static void rekey_seq_generator(void *private_);

static DECLARE_WORK(rekey_work, rekey_seq_generator, NULL);
static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator, NULL);

/*
* Lock avoidance:
Expand Down
2 changes: 1 addition & 1 deletion drivers/char/tty_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -3580,7 +3580,7 @@ static void initialize_tty_struct(struct tty_struct *tty)
tty->overrun_time = jiffies;
tty->buf.head = tty->buf.tail = NULL;
tty_buffer_init(tty);
INIT_WORK(&tty->buf.work, flush_to_ldisc, tty);
INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc, tty);
init_MUTEX(&tty->buf.pty_sem);
mutex_init(&tty->termios_mutex);
init_waitqueue_head(&tty->write_wait);
Expand Down
4 changes: 2 additions & 2 deletions fs/aio.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)

INIT_LIST_HEAD(&ctx->active_reqs);
INIT_LIST_HEAD(&ctx->run_list);
INIT_WORK(&ctx->wq, aio_kick_handler, ctx);
INIT_DELAYED_WORK(&ctx->wq, aio_kick_handler, ctx);

if (aio_setup_ring(ctx) < 0)
goto out_freectx;
Expand Down Expand Up @@ -876,7 +876,7 @@ static void aio_kick_handler(void *data)
* we're in a worker thread already, don't use queue_delayed_work,
*/
if (requeue)
queue_work(aio_wq, &ctx->wq);
queue_delayed_work(aio_wq, &ctx->wq, 0);
}


Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ static struct nfs_client *nfs_alloc_client(const char *hostname,
INIT_LIST_HEAD(&clp->cl_state_owners);
INIT_LIST_HEAD(&clp->cl_unused);
spin_lock_init(&clp->cl_lock);
INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
clp->cl_boot_time = CURRENT_TIME;
clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
Expand Down
3 changes: 2 additions & 1 deletion fs/nfs/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
static void nfs_expire_automounts(void *list);

LIST_HEAD(nfs_automount_list);
static DECLARE_WORK(nfs_automount_task, nfs_expire_automounts, &nfs_automount_list);
static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts,
&nfs_automount_list);
int nfs_mountpoint_expiry_timeout = 500 * HZ;

static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
Expand Down
2 changes: 1 addition & 1 deletion include/linux/aio.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ struct kioctx {

struct aio_ring_info ring_info;

struct work_struct wq;
struct delayed_work wq;
};

/* prototypes */
Expand Down
2 changes: 1 addition & 1 deletion include/linux/kbd_kern.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ static inline void con_schedule_flip(struct tty_struct *t)
if (t->buf.tail != NULL)
t->buf.tail->commit = t->buf.tail->used;
spin_unlock_irqrestore(&t->buf.lock, flags);
schedule_work(&t->buf.work);
schedule_delayed_work(&t->buf.work, 0);
}

#endif
4 changes: 2 additions & 2 deletions include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,8 +568,8 @@ struct ata_port {
struct ata_host *host;
struct device *dev;

struct work_struct port_task;
struct work_struct hotplug_task;
struct delayed_work port_task;
struct delayed_work hotplug_task;
struct work_struct scsi_rescan_task;

unsigned int hsm_task_state;
Expand Down
2 changes: 1 addition & 1 deletion include/linux/nfs_fs_sb.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct nfs_client {

unsigned long cl_lease_time;
unsigned long cl_last_renewal;
struct work_struct cl_renewd;
struct delayed_work cl_renewd;

struct rpc_wait_queue cl_rpcwaitq;

Expand Down
2 changes: 1 addition & 1 deletion include/linux/sunrpc/rpc_pipe_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct rpc_inode {
#define RPC_PIPE_WAIT_FOR_OPEN 1
int flags;
struct rpc_pipe_ops *ops;
struct work_struct queue_timeout;
struct delayed_work queue_timeout;
};

static inline struct rpc_inode *
Expand Down
2 changes: 1 addition & 1 deletion include/linux/sunrpc/xprt.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ struct rpc_xprt {
unsigned long connect_timeout,
bind_timeout,
reestablish_timeout;
struct work_struct connect_worker;
struct delayed_work connect_worker;
unsigned short port;

/*
Expand Down
2 changes: 1 addition & 1 deletion include/linux/tty.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ struct tty_buffer {
};

struct tty_bufhead {
struct work_struct work;
struct delayed_work work;
struct semaphore pty_sem;
spinlock_t lock;
struct tty_buffer *head; /* Queue head */
Expand Down
44 changes: 32 additions & 12 deletions include/linux/workqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ struct work_struct {
void (*func)(void *);
void *data;
void *wq_data;
};

struct delayed_work {
struct work_struct work;
struct timer_list timer;
};

Expand All @@ -28,32 +32,48 @@ struct execute_work {
.entry = { &(n).entry, &(n).entry }, \
.func = (f), \
.data = (d), \
}

#define __DELAYED_WORK_INITIALIZER(n, f, d) { \
.work = __WORK_INITIALIZER((n).work, (f), (d)), \
.timer = TIMER_INITIALIZER(NULL, 0, 0), \
}

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

#define DECLARE_DELAYED_WORK(n, f, d) \
struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, d)

/*
* initialize a work-struct's func and data pointers:
* initialize a work item's function and data pointers
*/
#define PREPARE_WORK(_work, _func, _data) \
do { \
(_work)->func = _func; \
(_work)->data = _data; \
(_work)->func = (_func); \
(_work)->data = (_data); \
} while (0)

#define PREPARE_DELAYED_WORK(_work, _func, _data) \
PREPARE_WORK(&(_work)->work, (_func), (_data))

/*
* initialize all of a work-struct:
* initialize all of a work item in one go
*/
#define INIT_WORK(_work, _func, _data) \
do { \
INIT_LIST_HEAD(&(_work)->entry); \
(_work)->pending = 0; \
PREPARE_WORK((_work), (_func), (_data)); \
} while (0)

#define INIT_DELAYED_WORK(_work, _func, _data) \
do { \
INIT_WORK(&(_work)->work, (_func), (_data)); \
init_timer(&(_work)->timer); \
} while (0)


extern struct workqueue_struct *__create_workqueue(const char *name,
int singlethread);
#define create_workqueue(name) __create_workqueue((name), 0)
Expand All @@ -62,24 +82,24 @@ extern struct workqueue_struct *__create_workqueue(const char *name,
extern void destroy_workqueue(struct workqueue_struct *wq);

extern int FASTCALL(queue_work(struct workqueue_struct *wq, struct work_struct *work));
extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, struct work_struct *work, unsigned long delay));
extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, unsigned long delay));
extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
struct work_struct *work, unsigned long delay);
struct delayed_work *work, unsigned long delay);
extern void FASTCALL(flush_workqueue(struct workqueue_struct *wq));

extern int FASTCALL(schedule_work(struct work_struct *work));
extern int FASTCALL(schedule_delayed_work(struct work_struct *work, unsigned long delay));
extern int FASTCALL(schedule_delayed_work(struct delayed_work *work, unsigned long delay));

extern int schedule_delayed_work_on(int cpu, struct work_struct *work, unsigned long delay);
extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay);
extern int schedule_on_each_cpu(void (*func)(void *info), void *info);
extern void flush_scheduled_work(void);
extern int current_is_keventd(void);
extern int keventd_up(void);

extern void init_workqueues(void);
void cancel_rearming_delayed_work(struct work_struct *work);
void cancel_rearming_delayed_work(struct delayed_work *work);
void cancel_rearming_delayed_workqueue(struct workqueue_struct *,
struct work_struct *);
struct delayed_work *);
int execute_in_process_context(void (*fn)(void *), void *,
struct execute_work *);

Expand All @@ -88,13 +108,13 @@ int execute_in_process_context(void (*fn)(void *), void *,
* function may still be running on return from cancel_delayed_work(). Run
* flush_scheduled_work() to wait on it.
*/
static inline int cancel_delayed_work(struct work_struct *work)
static inline int cancel_delayed_work(struct delayed_work *work)
{
int ret;

ret = del_timer_sync(&work->timer);
if (ret)
clear_bit(0, &work->pending);
clear_bit(0, &work->work.pending);
return ret;
}

Expand Down
Loading

0 comments on commit 52bad64

Please sign in to comment.