satur9nine
satur9nine

Reputation: 15092

How to queue the same workqueue work multiple times in Linux?

I see that when the schedule_work function is invoked it will not put the work task into the queue if it is already queued. However I want to queue the same task to be run multiple times even if it is already on the queue. How can I do this?

From workqueue.h:

/**
 * schedule_work - put work task in global workqueue
 * @work: job to be done
 *
 * Returns %false if @work was already on the kernel-global workqueue and
 * %true otherwise.
 *
 * This puts a job in the kernel-global workqueue if it was not already
 * queued and leaves it in the same position on the kernel-global
 * workqueue otherwise.
 */
static inline bool schedule_work(struct work_struct *work)

Upvotes: 1

Views: 3987

Answers (1)

Tsyvarev
Tsyvarev

Reputation: 66278

Workqueue expects every work structure to represent single "task", which is needed to be run once.

So, then simplest way to run a task several times - create new work structure every time.

Alternatively, as repeating the work while it is running is something unusual for workqueue, you may create your own kernel thread for execute some function repeatedly:

DECLARE_WAITQUEUE(repeat_wq); // Kernel thread will wait on this workqueue.
int n_works = 0; // Number of work requests to process.

// Thread function
void repeat_work(void* unused)
{
    spin_lock_irq(repeat_wq.lock); // Reuse workqueue's spinlock for our needs
    while(1) {
        // Wait until work request or thread should be stopped
        wait_event_interruptible_locked(&repeat_wq,
            n_works || kthread_should_stop());
        if(kthread_should_stop()) break;
        spin_unlock_irq(repeat_wq.lock);

        <do the work>

        // Acquire the lock for decrement count and recheck condition
        spin_lock_irq(repeat_wq.lock);
        n_works--;
    }
    // Finally release the lock
    spin_unlock_irq(repeat_wq.lock);
}

// Request new work.
void add_work(void)
{
    unsigned long flags;
    spin_lock_irqsave(repeat_wq.lock, flags);
    n_works++;
    wake_up_locked(&repeat_wq);
    spin_unlock_irqrestore(repeat_wq.lock, flags);      
}

Workqueues are kernel threads too, with a specific thread function kthread_worker_fn().

Upvotes: 2

Related Questions