workqueue: implement WQ_NON_REENTRANT
[pandora-kernel.git] / include / linux / workqueue.h
index 9466e86..07cf5e5 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/linkage.h>
 #include <linux/bitops.h>
 #include <linux/lockdep.h>
+#include <linux/threads.h>
 #include <asm/atomic.h>
 
 struct workqueue_struct;
@@ -22,12 +23,48 @@ typedef void (*work_func_t)(struct work_struct *work);
  */
 #define work_data_bits(work) ((unsigned long *)(&(work)->data))
 
+enum {
+       WORK_STRUCT_PENDING_BIT = 0,    /* work item is pending execution */
+       WORK_STRUCT_LINKED_BIT  = 1,    /* next work is linked to this one */
+#ifdef CONFIG_DEBUG_OBJECTS_WORK
+       WORK_STRUCT_STATIC_BIT  = 2,    /* static initializer (debugobjects) */
+       WORK_STRUCT_COLOR_SHIFT = 3,    /* color for workqueue flushing */
+#else
+       WORK_STRUCT_COLOR_SHIFT = 2,    /* color for workqueue flushing */
+#endif
+
+       WORK_STRUCT_COLOR_BITS  = 4,
+
+       WORK_STRUCT_PENDING     = 1 << WORK_STRUCT_PENDING_BIT,
+       WORK_STRUCT_LINKED      = 1 << WORK_STRUCT_LINKED_BIT,
+#ifdef CONFIG_DEBUG_OBJECTS_WORK
+       WORK_STRUCT_STATIC      = 1 << WORK_STRUCT_STATIC_BIT,
+#else
+       WORK_STRUCT_STATIC      = 0,
+#endif
+
+       /*
+        * The last color is no color used for works which don't
+        * participate in workqueue flushing.
+        */
+       WORK_NR_COLORS          = (1 << WORK_STRUCT_COLOR_BITS) - 1,
+       WORK_NO_COLOR           = WORK_NR_COLORS,
+
+       /*
+        * Reserve 6 bits off of cwq pointer w/ debugobjects turned
+        * off.  This makes cwqs aligned to 64 bytes which isn't too
+        * excessive while allowing 15 workqueue flush colors.
+        */
+       WORK_STRUCT_FLAG_BITS   = WORK_STRUCT_COLOR_SHIFT +
+                                 WORK_STRUCT_COLOR_BITS,
+
+       WORK_STRUCT_FLAG_MASK   = (1UL << WORK_STRUCT_FLAG_BITS) - 1,
+       WORK_STRUCT_WQ_DATA_MASK = ~WORK_STRUCT_FLAG_MASK,
+       WORK_STRUCT_NO_CPU      = NR_CPUS << WORK_STRUCT_FLAG_BITS,
+};
+
 struct work_struct {
        atomic_long_t data;
-#define WORK_STRUCT_PENDING 0          /* T if work item pending execution */
-#define WORK_STRUCT_STATIC  1          /* static initializer (debugobjects) */
-#define WORK_STRUCT_FLAG_MASK (3UL)
-#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
        struct list_head entry;
        work_func_t func;
 #ifdef CONFIG_LOCKDEP
@@ -35,8 +72,9 @@ struct work_struct {
 #endif
 };
 
-#define WORK_DATA_INIT()       ATOMIC_LONG_INIT(0)
-#define WORK_DATA_STATIC_INIT()        ATOMIC_LONG_INIT(2)
+#define WORK_DATA_INIT()       ATOMIC_LONG_INIT(WORK_STRUCT_NO_CPU)
+#define WORK_DATA_STATIC_INIT()        \
+       ATOMIC_LONG_INIT(WORK_STRUCT_NO_CPU | WORK_STRUCT_STATIC)
 
 struct delayed_work {
        struct work_struct work;
@@ -96,9 +134,14 @@ struct execute_work {
 #ifdef CONFIG_DEBUG_OBJECTS_WORK
 extern void __init_work(struct work_struct *work, int onstack);
 extern void destroy_work_on_stack(struct work_struct *work);
+static inline unsigned int work_static(struct work_struct *work)
+{
+       return *work_data_bits(work) & WORK_STRUCT_STATIC;
+}
 #else
 static inline void __init_work(struct work_struct *work, int onstack) { }
 static inline void destroy_work_on_stack(struct work_struct *work) { }
+static inline unsigned int work_static(struct work_struct *work) { return 0; }
 #endif
 
 /*
@@ -162,7 +205,7 @@ static inline void destroy_work_on_stack(struct work_struct *work) { }
  * @work: The work item in question
  */
 #define work_pending(work) \
-       test_bit(WORK_STRUCT_PENDING, work_data_bits(work))
+       test_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))
 
 /**
  * delayed_work_pending - Find out whether a delayable work item is currently
@@ -177,16 +220,20 @@ static inline void destroy_work_on_stack(struct work_struct *work) { }
  * @work: The work item in question
  */
 #define work_clear_pending(work) \
-       clear_bit(WORK_STRUCT_PENDING, work_data_bits(work))
+       clear_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))
 
+enum {
+       WQ_FREEZEABLE           = 1 << 0, /* freeze during suspend */
+       WQ_SINGLE_CPU           = 1 << 1, /* only single cpu at a time */
+       WQ_NON_REENTRANT        = 1 << 2, /* guarantee non-reentrance */
+};
 
 extern struct workqueue_struct *
-__create_workqueue_key(const char *name, int singlethread,
-                      int freezeable, int rt, struct lock_class_key *key,
-                      const char *lock_name);
+__create_workqueue_key(const char *name, unsigned int flags, int max_active,
+                      struct lock_class_key *key, const char *lock_name);
 
 #ifdef CONFIG_LOCKDEP
-#define __create_workqueue(name, singlethread, freezeable, rt) \
+#define __create_workqueue(name, flags, max_active)            \
 ({                                                             \
        static struct lock_class_key __key;                     \
        const char *__lock_name;                                \
@@ -196,20 +243,20 @@ __create_workqueue_key(const char *name, int singlethread,
        else                                                    \
                __lock_name = #name;                            \
                                                                \
-       __create_workqueue_key((name), (singlethread),          \
-                              (freezeable), (rt), &__key,      \
-                              __lock_name);                    \
+       __create_workqueue_key((name), (flags), (max_active),   \
+                               &__key, __lock_name);           \
 })
 #else
-#define __create_workqueue(name, singlethread, freezeable, rt) \
-       __create_workqueue_key((name), (singlethread), (freezeable), (rt), \
-                              NULL, NULL)
+#define __create_workqueue(name, flags, max_active)            \
+       __create_workqueue_key((name), (flags), (max_active), NULL, NULL)
 #endif
 
-#define create_workqueue(name) __create_workqueue((name), 0, 0, 0)
-#define create_rt_workqueue(name) __create_workqueue((name), 0, 0, 1)
-#define create_freezeable_workqueue(name) __create_workqueue((name), 1, 1, 0)
-#define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0, 0)
+#define create_workqueue(name)                                 \
+       __create_workqueue((name), 0, 1)
+#define create_freezeable_workqueue(name)                      \
+       __create_workqueue((name), WQ_FREEZEABLE | WQ_SINGLE_CPU, 1)
+#define create_singlethread_workqueue(name)                    \
+       __create_workqueue((name), WQ_SINGLE_CPU, 1)
 
 extern void destroy_workqueue(struct workqueue_struct *wq);
 
@@ -297,4 +344,11 @@ static inline long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
 #else
 long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg);
 #endif /* CONFIG_SMP */
+
+#ifdef CONFIG_FREEZER
+extern void freeze_workqueues_begin(void);
+extern bool freeze_workqueues_busy(void);
+extern void thaw_workqueues(void);
+#endif /* CONFIG_FREEZER */
+
 #endif