1/*-
2 * Copyright (c) 2010 Isilon Systems, Inc.
3 * Copyright (c) 2010 iX Systems, Inc.
4 * Copyright (c) 2010 Panasas, Inc.
5 * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice unmodified, this list of conditions, and the following
13 *    disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29#ifndef	_LINUXKPI_LINUX_WORKQUEUE_H_
30#define	_LINUXKPI_LINUX_WORKQUEUE_H_
31
32#include "pthread.h"
33#include "los_task.h"
34#include "semaphore.h"
35#include "los_memory.h"
36#include "los_event.h"
37#include "linux/list.h"
38#include "linux/timer.h"
39
40#ifdef __cplusplus
41#if __cplusplus
42extern "C" {
43#endif /* __cplusplus */
44#endif /* __cplusplus */
45
46
47struct lock_class_key {
48};
49
50#ifdef WORKQUEUE_SUPPORT_PRIORITY
51/**
52 * @ingroup los_task
53 * Define a usable work priority.
54 *
55 * Highest task priority.
56 */
57#define OS_WORK_PRIORITY_HIGHEST                    0
58
59/**
60 * @ingroup los_task
61 * Define a usable work priority.
62 *
63 * Lowest task priority.
64 */
65#define OS_WORK_PRIORITY_LOWEST                     31
66
67
68/**
69 * @ingroup los_task
70 * Define a usable work priority.
71 *
72 * Default task priority.
73 */
74#define OS_WORK_PRIORITY_DEFAULT                     OS_WORK_PRIORITY_LOWEST
75#endif
76
77/**
78 * @ingroup workqueue
79 * System default workqueue.
80 */
81extern struct workqueue_struct *g_pstSystemWq;
82
83/**
84 * @ingroup workqueue
85 * Workqueue task control block structure.
86 */
87typedef struct LosTaskCB task_struct;
88
89/**
90 * @ingroup workqueue
91 * Define atomic_long_t as a signed integer.
92 *
93 */
94typedef long atomic_long_t;
95
96struct work_struct;
97
98/**
99 * @ingroup workqueue
100 * Workqueue handling function.
101 */
102typedef void (*work_func_t)(struct work_struct *);
103
104/**
105 * @ingroup workqueue
106 * Work structure.
107 * A work is a node in a workqueue.
108 */
109struct work_struct {
110    atomic_long_t data;        /**< Input parameter of the work handling function. */
111    struct list_head entry;    /**< Pointer to a doubly linked list of a work. */
112    work_func_t func;          /**< Work handling function. */
113    unsigned int work_status;  /**< Work status. */
114#ifdef WORKQUEUE_SUPPORT_PRIORITY
115    unsigned int work_pri;
116#endif
117};
118
119/**
120 * @ingroup workqueue
121 * delayed_work structure.
122 * A delayed_work is a work that is delayed to be mounted to a workqueue.
123 */
124struct delayed_work {
125    struct work_struct work;        /**< Work structure. */
126    struct timer_list timer;        /**< Delay control block parameter structure. */
127    struct workqueue_struct *wq;    /**< Workqueue that contains the delayed_work structure. */
128    int cpu;                        /**< Number of CPUs. Not in use temporarily. */
129};
130
131/**
132 * @ingroup workqueue
133 * Workqueue control structure.
134 * It awakes a workqueue or makes a workqueue sleep.
135 */
136typedef struct tag_cpu_workqueue_struct {
137    struct list_head worklist;         /**< Pointer to a work doubly linked list. */
138    struct work_struct *current_work;  /**< Work that is being executed. */
139    struct workqueue_struct *wq;       /**< Workqueue that contains the workqueue control structure. */
140    task_struct *thread;               /**< Workqueue handling thread. */
141} cpu_workqueue_struct;
142
143/**
144 * @ingroup workqueue
145 * Definition of a workqueue structure.
146 */
147struct workqueue_struct {
148    cpu_workqueue_struct *cpu_wq;   /**< Workqueue control structure. */
149    struct list_head list;          /**< Pointer to a workqueue doubly linked list. */
150    EVENT_CB_S wq_event;            /**< Event of a workqueue. */
151    unsigned int wq_id;             /**< Workqueue ID. */
152    int delayed_work_count;         /**< Number of delayed works in a workqueue. */
153    char *name;                     /**< Workqueue name. */
154    int singlethread;               /**< Whether to create a new working task. 0 indicates that
155                                         the default working task will be used. */
156    int wq_status;                  /**< Workqueue status. */
157    int freezeable;                 /**< Not in use temporarily. */
158    int rt;                         /**< Not in use temporarily. */
159};
160
161/**
162 * @ingroup workqueue
163 * Work status enumeration.
164 */
165enum work_status {
166    WORK_BUSY_PENDING   = 1U << 0,    /**< The status of work item is pending execution. */
167    WORK_BUSY_RUNNING   = 1U << 1,    /**< The status of work item is running. */
168    WORK_STRUCT_PENDING = 1U << 0,    /**< Work item is pending execution. */
169    WORK_STRUCT_RUNNING = 1U << 1,    /**< Work item is running. */
170};
171
172/**
173 * @ingroup workqueue
174 * Initialize a work.
175 */
176#ifdef WORKQUEUE_SUPPORT_PRIORITY
177#define INIT_WORK(work, callbackFunc)  do {      \
178    INIT_LIST_HEAD(&((work)->entry));            \
179    (work)->func = (callbackFunc);               \
180    (work)->data = (atomic_long_t)(0);           \
181    (work)->work_status = 0;                     \
182    (work)->work_pri = OS_WORK_PRIORITY_DEFAULT; \
183} while (0)
184#else
185#define INIT_WORK(work, callbackFunc)  do { \
186    INIT_LIST_HEAD(&((work)->entry));       \
187    (work)->func = (callbackFunc);          \
188    (work)->data = (atomic_long_t)(0);      \
189    (work)->work_status = 0;                \
190} while (0)
191#endif
192
193/**
194 * @ingroup workqueue
195 * Initialize a delayed work.
196 */
197#define INIT_DELAYED_WORK(work, func) \
198    linux_init_delayed_work(work, func)
199
200#define create_singlethread_workqueue(name) \
201    linux_create_singlethread_workqueue(name)
202
203#define create_workqueue(name) \
204    linux_create_singlethread_workqueue(name)
205
206#define destroy_workqueue(wq) \
207    linux_destroy_workqueue(wq)
208
209#define queue_work(wq, work) \
210    linux_queue_work(wq, work)
211
212#define queue_delayed_work(wq, dwork, delayTime) \
213    linux_queue_delayed_work(wq, dwork, delayTime)
214
215#define schedule_work(work) \
216    linux_schedule_work(work)
217
218#define schedule_delayed_work(dwork, delayTime) \
219    linux_schedule_delayed_work(dwork, delayTime)
220
221#define work_busy(work) \
222    linux_work_busy(work)
223
224#define flush_delayed_work(dwork) \
225    linux_flush_delayed_work(dwork)
226
227#define cancel_delayed_work(dwork) \
228    linux_cancel_delayed_work(dwork)
229
230#define cancel_delayed_work_sync(dwork) \
231    linux_cancel_delayed_work_sync(dwork)
232
233#define flush_work(work) \
234    linux_flush_work(work)
235
236#define cancel_work_sync(work) \
237    linux_cancel_work_sync(work)
238
239/* prototypes */
240
241/**
242 * @ingroup  workqueue
243 * @brief Initialize a delayed work.
244 *
245 * @par Description:
246 * This API is used to initialize a delayed work.
247 *
248 * @attention
249 * <ul>
250 * <li>The parameter dwork and func shoud be valid memory, otherwise, the system may be abnormal. </li>
251 * </ul>
252 *
253 * @param  dwork   [IN] Work handle.
254 * @param  func    [IN] Executive function.
255 *
256 * @retval  None.
257 * @par Dependency:
258 * <ul><li>workqueue.h: the header file that contains the API declaration.</li></ul>
259 * @see none.
260 */
261extern void linux_init_delayed_work(struct delayed_work *dwork, work_func_t func);
262
263/**
264 * @ingroup  workqueue
265 * @brief Create a workqueue.
266 *
267 * @par Description:
268 * This API is used to create a workqueue that has a specified name.
269 *
270 * @attention
271 * <ul>
272 * <li> The passed-in workqueue name is a character string that cannot be null
273 * and is the only identifier of the workqueue, make sure it is unique. </li>
274 * </ul>
275 *
276 * @param  name  [IN] Workqueue name.
277 *
278 * @retval  NULL                   The workqueue fails to be created.
279 * @retval  workqueue_struct*      The workqueue is successfully created.
280 * @par Dependency:
281 * <ul><li>workqueue.h: the header file that contains the API declaration.</li></ul>
282 * @see destroy_workqueue
283 */
284extern struct workqueue_struct *linux_create_singlethread_workqueue(char *name);
285
286/**
287 * @ingroup  workqueue
288 * @brief Delete a workqueue.
289 *
290 * @par Description:
291 * This API is used to delete a workqueue that has a specified handle.
292 *
293 * @attention
294 * <ul>
295 * <li>The name of the workqueue will be null and the workqueue cannot be used again
296 * after the workqueue is deleted. </li>
297 * </ul>
298 *
299 * @param  wq  [IN] Workqueue handle.
300 *
301 * @retval  None.
302 * @par Dependency:
303 * <ul><li>workqueue.h: the header file that contains the API declaration.</li></ul>
304 * @see create_workqueue
305 */
306extern void linux_destroy_workqueue(struct workqueue_struct *wq);
307
308/**
309 * @ingroup  workqueue
310 * @brief Queue a work on a workqueue.
311 *
312 * @par Description:
313 * This API is used to queue a work on a specified workqueue.
314 *
315 * @attention
316 * <ul>
317 * <li>The parameter wq and work shoud be valid memory, otherwise, the system may be abnormal. </li>
318 * <li>The work will be immediately queued on the workqueue. </li>
319 * </ul>
320 *
321 * @param  wq     [IN] Workqueue handle.
322 * @param  work  [IN] Work handle.
323 *
324 * @retval #TRUE      The work is successfully queued on the workqueue.
325 * @retval #FALSE     The work fails to be queued on the workqueue.
326 * @par Dependency:
327 * <ul>
328 * <li>This function should be used after create_singlethread_workqueue() or create_workqueue() has been called</li>
329 * <li>workqueue.h: the header file that contains the API declaration.</li>
330 * </ul>
331 * @see cancel_work_sync
332 */
333extern bool linux_queue_work(struct workqueue_struct *wq, struct work_struct *work);
334
335/**
336 * @ingroup  workqueue
337 * @brief Queue a work on a workqueue after delay.
338 *
339 * @par Description:
340 * This API is used to queue a work on a specified workqueue after delay.
341 *
342 * @attention
343 * <ul>
344 * <li>The parameter wq and dwork shoud be valid memory, otherwise, the system may be abnormal. </li>
345 * <li>The work will be queued on the workqueue in a delayed period of time. </li>
346 * <li>The work will be queued on the workqueue immediately if delayTime is 0, it as same as queue_work(). </li>
347 * </ul>
348 *
349 * @param  wq         [IN] Workqueue handle.
350 * @param  dwork      [IN] Delayed work handle.
351 * @param  delayTime  [IN] Delayed time, number of ticks to wait or 0 for immediate execution.
352 *
353 * @retval #TRUE      The work is successfully queued on the workqueue.
354 * @retval #FALSE     The work fails to be queued on the workqueue.
355 * @par Dependency:
356 * <ul>
357 * <li>This function should be used after create_singlethread_workqueue() or create_workqueue() has been called</li>
358 * <li>workqueue.h: the header file that contains the API declaration.</li>
359 * </ul>
360 * @see cancel_delayed_work
361 */
362extern bool linux_queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork, unsigned int delayTime);
363
364/**
365 * @ingroup  workqueue
366 * @brief Put a work in a default workqueue.
367 *
368 * @par Description:
369 * This API is used to put a work in the default workqueue that is created when Huawei LiteOS is initialized.
370 *
371 * @attention
372 * <ul>
373 * <li>The parameter work shoud be valid memory, otherwise, the system may be abnormal. </li>
374 * <li>The default workqueue is g_pstSystemWq. </li>
375 * </ul>
376 *
377 * @param  work        [IN] Work handle.
378 *
379 * @retval #TRUE      The work is successfully put in the workqueue.
380 * @retval #FALSE     The work fails to be put in the workqueue.
381 * @par Dependency:
382 * <ul>
383 * <li>This function should be used after create_singlethread_workqueue() or create_workqueue() has been called</li>
384 * <li>workqueue.h: the header file that contains the API declaration.</li>
385 * </ul>
386 * @see cancel_work_sync
387 */
388extern bool linux_schedule_work(struct work_struct *work);
389
390/**
391 * @ingroup  workqueue
392 * @brief Put a work in a default workqueue after delay.
393 *
394 * @par Description:
395 * This API is used to put a work in the default workqueue that is created
396 * when Huawei LiteOS is initialized in a delayed period of time.
397 *
398 * @attention
399 * <ul>
400 * <li>The parameter dwork shoud be valid memory, otherwise, the system may be abnormal. </li>
401 * <li>The default workqueue is g_pstSystemWq. </li>
402 * <li>The dwork will be queued on the workqueue immediately if delayTime is 0. </li>
403 * </ul>
404 *
405 * @param  dwork         [IN] Delayed work handle.
406 * @param  delayTime     [IN] Delayed time, number of ticks to wait or 0 for immediate execution.
407 *
408 * @retval #TRUE      The work is successfully put in the workqueue.
409 * @retval #FALSE     The work fails to be put in the workqueue.
410 * @par Dependency:
411 * <ul>
412 * <li>This function should be used after create_singlethread_workqueue() or create_workqueue() has been called</li>
413 * <li>workqueue.h: the header file that contains the API declaration.</li>
414 * </ul>
415 * @see cancel_delayed_work
416 */
417extern bool linux_schedule_delayed_work(struct delayed_work *dwork, unsigned int delayTime);
418
419/**
420 * @ingroup  workqueue
421 * @brief Query the work status.
422 *
423 * @par Description:
424 * This API is used to query the status of a work and a delayed work.
425 *
426 * @attention
427 * <ul>
428 * <li>The parameter work shoud be valid memory, otherwise, the system may be abnormal.</li>
429 * </ul>
430 *
431 * @param  work          [IN] Work handle.
432 *
433 * @retval #WORK_BUSY_PENDING      The work is pending.
434 * @retval #WORK_BUSY_RUNNING      The work is running.
435 * @retval #FALSE                  The value of the parameter work is NULL.
436 * @par Dependency:
437 * <ul><li>workqueue.h: the header file that contains the API declaration.</li></ul>
438 * @see None.
439 */
440extern unsigned int linux_work_busy(struct work_struct *work);
441
442/**
443 * @ingroup  workqueue
444 * @brief Immediately execute a delayed work.
445 *
446 * @par Description:
447 * This API is used to immediately put a delayed work in a workqueue
448 * and wait for the execution of the delayed work to end.
449 *
450 * @attention
451 * <ul>
452 * <li>flush_delayed_work() should be used after queue_delayed_work() has been called.</li>
453 * <li>The parameter dwork shoud be valid memory, otherwise, the system may be abnormal.</li>
454 * </ul>
455 *
456 * @param  dwork          [IN] Delayed work handle.
457 *
458 * @retval #TRUE      The operation succeeds.
459 * @retval #FALSE     The operation fails.
460 * @par Dependency
461 * <ul><li>workqueue.h: the header file that contains the API declaration.</li></ul>
462 * @see None.
463 */
464extern bool linux_flush_delayed_work(struct delayed_work *dwork);
465
466/**
467 * @ingroup  workqueue
468 * @brief Cancel a delayed work.
469 *
470 * @par Description:
471 * This API is used to cancel a delayed work, which means that the work will not be executed regardless of
472 * whether the delayed time has expired.
473 *
474 * @attention
475 * <ul>
476 * <li>cancel_delayed_work() should be used after queue_delayed_work() has been called.</li>
477 * <li>The parameter dwork shoud be valid memory, otherwise, the system may be abnormal.</li>
478 * </ul>
479 *
480 * @param  dwork          [IN] Delayed work handle.
481 *
482 * @retval #TRUE      The delayed work is successfully canceled.
483 * @retval #FALSE     The delayed work fails to be canceled.
484 * @par Dependency:
485 * <ul><li>workqueue.h: the header file that contains the API declaration.</li></ul>
486 * @see queue_delayed_work
487 */
488extern bool linux_cancel_delayed_work(struct delayed_work *dwork);
489/**
490 * @ingroup  workqueue
491 * @brief Cancel a delayed work and wait for it to finish.
492 *
493 * @par Description:
494 * This API is used to cancel a delayed work, which means that the work will not be executed regardless of
495 * whether the delayed time has expired.
496 *
497 * @attention
498 * <ul>
499 * <li>cancel_delayed_work_sync() should be used after queue_delayed_work() has been called.</li>
500 * <li>The parameter dwork shoud be valid memory, otherwise, the system may be abnormal.</li>
501 * </ul>
502 *
503 * @param  dwork          [IN] Delayed work handle.
504 *
505 * @retval #TRUE      The delayed work is successfully canceled.
506 * @retval #FALSE     The delayed work fails to be canceled.
507 * @par Dependency:
508 * <ul><li>workqueue.h: the header file that contains the API declaration.</li></ul>
509 * @see queue_delayed_work
510 */
511extern bool linux_cancel_delayed_work_sync(struct delayed_work *dwork);
512
513/**
514 * @ingroup  workqueue
515 * @brief Immediately execute a work.
516 *
517 * @par Description:
518 * This API is used to immediately execute a specified work and wait for the execution to end.
519 *
520 * @attention
521 * <ul>
522 * <li>flush_work() should be used after queue_work() has been called.</li>
523 * <li>The parameter work shoud be valid memory, otherwise, the system may be abnormal.</li>
524 * </ul>
525 *
526 * @param  work          [IN] Work handle.
527 *
528 * @retval #TRUE      The operation succeeds.
529 * @retval #FALSE     The operation fails.
530 * @par Dependency:
531 * <ul><li>workqueue.h: the header file that contains the API declaration.</li></ul>
532 * @see None.
533 */
534extern bool linux_flush_work(struct work_struct *work);
535
536/**
537 * @ingroup  workqueue
538 * @brief Cancel a work.
539 *
540 * @par Description:
541 * This API is used to cancel a work that is pending or running.
542 *
543 * @attention
544 * <ul>
545 * <li>cancel_work_sync() should be used after queue_work() has been called.</li>
546 * <li>The parameter work shoud be valid memory, otherwise, the system may be abnormal.</li>
547 * </ul>
548 *
549 * @param  work          [IN] Work handle.
550 *
551 * @retval #TRUE      The work is successfully canceled.
552 * @retval #FALSE     The work fails to be canceled.
553 * @par Dependency:
554 * <ul><li>workqueue.h: the header file that contain the API declaration.</li></ul>
555 * @see queue_work
556 */
557extern bool linux_cancel_work_sync(struct work_struct *work);
558
559#ifdef __cplusplus
560#if __cplusplus
561}
562#endif /* __cplusplus */
563#endif /* __cplusplus */
564
565#endif /* _LINUXKPI_LINUX_WORKQUEUE_H_ */
566