Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 206212
b: refs/heads/master
c: 0f90004
h: refs/heads/master
v: v3
  • Loading branch information
Tejun Heo committed Jun 29, 2010
1 parent c8df028 commit 12a82f6
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 7 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1537663f5763892cacf1409ac0efef1b4f332d1e
refs/heads/master: 0f900049cbe2767d47c2a62b54f0e822e1d66840
5 changes: 4 additions & 1 deletion trunk/include/linux/workqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ enum {
WORK_STRUCT_PENDING_BIT = 0, /* work item is pending execution */
#ifdef CONFIG_DEBUG_OBJECTS_WORK
WORK_STRUCT_STATIC_BIT = 1, /* static initializer (debugobjects) */
WORK_STRUCT_FLAG_BITS = 2,
#else
WORK_STRUCT_FLAG_BITS = 1,
#endif

WORK_STRUCT_PENDING = 1 << WORK_STRUCT_PENDING_BIT,
Expand All @@ -35,7 +38,7 @@ enum {
WORK_STRUCT_STATIC = 0,
#endif

WORK_STRUCT_FLAG_MASK = 3UL,
WORK_STRUCT_FLAG_MASK = (1UL << WORK_STRUCT_FLAG_BITS) - 1,
WORK_STRUCT_WQ_DATA_MASK = ~WORK_STRUCT_FLAG_MASK,
};

Expand Down
60 changes: 55 additions & 5 deletions trunk/kernel/workqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@

/*
* The per-CPU workqueue (if single thread, we always use the first
* possible cpu).
* possible cpu). The lower WORK_STRUCT_FLAG_BITS of
* work_struct->data are used for flags and thus cwqs need to be
* aligned at two's power of the number of flag bits.
*/
struct cpu_workqueue_struct {

Expand All @@ -59,7 +61,7 @@ struct cpu_workqueue_struct {

struct workqueue_struct *wq; /* I: the owning workqueue */
struct task_struct *thread;
} ____cacheline_aligned;
};

/*
* The externally visible workqueue abstraction is an array of
Expand Down Expand Up @@ -967,6 +969,53 @@ int current_is_keventd(void)

}

static struct cpu_workqueue_struct *alloc_cwqs(void)
{
/*
* cwqs are forced aligned according to WORK_STRUCT_FLAG_BITS.
* Make sure that the alignment isn't lower than that of
* unsigned long long.
*/
const size_t size = sizeof(struct cpu_workqueue_struct);
const size_t align = max_t(size_t, 1 << WORK_STRUCT_FLAG_BITS,
__alignof__(unsigned long long));
struct cpu_workqueue_struct *cwqs;
#ifndef CONFIG_SMP
void *ptr;

/*
* On UP, percpu allocator doesn't honor alignment parameter
* and simply uses arch-dependent default. Allocate enough
* room to align cwq and put an extra pointer at the end
* pointing back to the originally allocated pointer which
* will be used for free.
*
* FIXME: This really belongs to UP percpu code. Update UP
* percpu code to honor alignment and remove this ugliness.
*/
ptr = __alloc_percpu(size + align + sizeof(void *), 1);
cwqs = PTR_ALIGN(ptr, align);
*(void **)per_cpu_ptr(cwqs + 1, 0) = ptr;
#else
/* On SMP, percpu allocator can do it itself */
cwqs = __alloc_percpu(size, align);
#endif
/* just in case, make sure it's actually aligned */
BUG_ON(!IS_ALIGNED((unsigned long)cwqs, align));
return cwqs;
}

static void free_cwqs(struct cpu_workqueue_struct *cwqs)
{
#ifndef CONFIG_SMP
/* on UP, the pointer to free is stored right after the cwq */
if (cwqs)
free_percpu(*(void **)per_cpu_ptr(cwqs + 1, 0));
#else
free_percpu(cwqs);
#endif
}

static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
{
struct workqueue_struct *wq = cwq->wq;
Expand Down Expand Up @@ -1012,7 +1061,7 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
if (!wq)
goto err;

wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct);
wq->cpu_wq = alloc_cwqs();
if (!wq->cpu_wq)
goto err;

Expand All @@ -1031,6 +1080,7 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
for_each_possible_cpu(cpu) {
struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);

BUG_ON((unsigned long)cwq & WORK_STRUCT_FLAG_MASK);
cwq->wq = wq;
cwq->cpu = cpu;
spin_lock_init(&cwq->lock);
Expand Down Expand Up @@ -1059,7 +1109,7 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
return wq;
err:
if (wq) {
free_percpu(wq->cpu_wq);
free_cwqs(wq->cpu_wq);
kfree(wq);
}
return NULL;
Expand Down Expand Up @@ -1112,7 +1162,7 @@ void destroy_workqueue(struct workqueue_struct *wq)
for_each_possible_cpu(cpu)
cleanup_workqueue_thread(get_cwq(cpu, wq));

free_percpu(wq->cpu_wq);
free_cwqs(wq->cpu_wq);
kfree(wq);
}
EXPORT_SYMBOL_GPL(destroy_workqueue);
Expand Down

0 comments on commit 12a82f6

Please sign in to comment.