FreeRTOS C-Addons  1.1.0
C-Addon functionality to FreeRTOS
workqueue.c
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2017, Michael Becker (michael.f.becker@gmail.com)
4  *
5  * This file is part of the FreeRTOS Add-ons project.
6  *
7  * Source Code:
8  * https://github.com/michaelbecker/freertos-addons
9  *
10  * Project Page:
11  * http://michaelbecker.github.io/freertos-addons/
12  *
13  * On-line Documentation:
14  * http://michaelbecker.github.io/freertos-addons/docs/html/index.html
15  *
16  * Permission is hereby granted, free of charge, to any person obtaining a
17  * copy of this software and associated documentation files
18  * (the "Software"), to deal in the Software without restriction, including
19  * without limitation the rights to use, copy, modify, merge, publish,
20  * distribute, sublicense, and/or sell copies of the Software, and to
21  * permit persons to whom the Software is furnished to do so,subject to the
22  * following conditions:
23  *
24  * + The above copyright notice and this permission notice shall be included
25  * in all copies or substantial portions of the Software.
26  * + Credit is appreciated, but not required, if you find this project
27  * useful enough to include in your application, product, device, etc.
28  *
29  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
30  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
33  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
34  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
35  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36  *
37  ***************************************************************************/
38 
39 
40 #include <stdlib.h>
41 #include "FreeRTOS.h"
42 #include "task.h"
43 #include "workqueue.h"
44 #include "queue_simple.h"
45 
46 
50 typedef struct pvtWorkItem_t_ {
51 
56 
61 
65  void *UserData;
66 
68 
69 
73 typedef struct pvtWorkQueue_t_ {
74 
79 
83  SemaphoreHandle_t Event;
84 
85  SemaphoreHandle_t Lock;
86 
87  TaskHandle_t WorkerThread;
88 
89 #if (INCLUDE_vTaskDelete == 1)
90 
94 
95 #endif
96 
98 
99 
100 
101 static void WorkerThread(void *parameters)
102 {
103  /****************************************/
104  pvtWorkQueue_t *WorkQueue;
105  DlNode_t *Node;
106  pvtWorkItem_t *WorkItem;
107 
108 #if (INCLUDE_vTaskDelete == 1)
109 
110  TaskHandle_t handle;
111  int ExitThread;
112 
113 #endif
114  /****************************************/
115 
116 
117  WorkQueue = (pvtWorkQueue_t*)parameters;
118 
119 
120  while (1) {
121 
125  xSemaphoreTake(WorkQueue->Event, portMAX_DELAY);
126 
130  xSemaphoreTake(WorkQueue->Lock, portMAX_DELAY);
131 
135  while ( !IsQueueEmpty(&WorkQueue->Queue)) {
139  Node = Dequeue(&WorkQueue->Queue);
140 
145  xSemaphoreGive(WorkQueue->Lock);
146 
150  WorkItem = CONTAINING_RECORD(Node, pvtWorkItem_t, Node);
151 
155  WorkItem->Function(WorkItem->UserData);
156 
160  free(WorkItem);
161 
166  xSemaphoreTake(WorkQueue->Lock, portMAX_DELAY);
167  }
168 
169 #if (INCLUDE_vTaskDelete == 1)
170 
174  ExitThread = WorkQueue->ExitThread;
175 
176 #endif
177 
180  xSemaphoreGive(WorkQueue->Lock);
181 
182 #if (INCLUDE_vTaskDelete == 1)
183 
186  if (ExitThread) {
187  break;
188  }
189 
190 #endif
191  }
192 
193 #if (INCLUDE_vTaskDelete == 1)
194 
202  xSemaphoreTake(WorkQueue->Lock, portMAX_DELAY);
203 
207  while ( !IsQueueEmpty(&WorkQueue->Queue)) {
208 
212  Node = Dequeue(&WorkQueue->Queue);
213 
217  WorkItem = CONTAINING_RECORD(Node, pvtWorkItem_t, Node);
218 
222  free(WorkItem);
223  }
224 
228  xSemaphoreGive(WorkQueue->Lock);
229 
233  vSemaphoreDelete(WorkQueue->Lock);
234  vSemaphoreDelete(WorkQueue->Event);
235 
239  handle = WorkQueue->WorkerThread;
240 
244  free(WorkQueue);
245 
249  vTaskDelete(handle);
250 
251 #endif
252 }
253 
254 
255 WorkQueue_t CreateWorkQueueEx( const char * const Name,
256  uint16_t StackSize,
257  UBaseType_t Priority)
258 {
259  /****************************/
260  pvtWorkQueue_t *WorkQueue;
261  BaseType_t rc;
262  /****************************/
263 
264  WorkQueue = (pvtWorkQueue_t *)malloc(sizeof(pvtWorkQueue_t));
265 
266  if (WorkQueue == NULL)
267  return NULL;
268 
269  InitQueue(&WorkQueue->Queue);
270 
271  WorkQueue->Event = xSemaphoreCreateBinary();
272 
273  if (WorkQueue->Event == NULL) {
274  free(WorkQueue);
275  return NULL;
276  }
277 
278  WorkQueue->Lock = xSemaphoreCreateMutex();
279 
280  if (WorkQueue->Lock == NULL) {
281  vSemaphoreDelete(WorkQueue->Event);
282  free(WorkQueue);
283  return NULL;
284  }
285 
286 #if (INCLUDE_vTaskDelete == 1)
287 
288  WorkQueue->ExitThread = 0;
289 
290 #endif
291 
292  rc = xTaskCreate( WorkerThread,
293  Name,
294  StackSize,
295  WorkQueue,
296  Priority,
297  &WorkQueue->WorkerThread);
298 
299  if (rc != pdPASS) {
300  vSemaphoreDelete(WorkQueue->Lock);
301  vSemaphoreDelete(WorkQueue->Event);
302  free(WorkQueue);
303  return NULL;
304  }
305 
306  return WorkQueue;
307 }
308 
309 
310 #if (INCLUDE_vTaskDelete == 1)
311 
313 {
314  /****************************/
315  pvtWorkQueue_t *WorkQueue;
316  /****************************/
317 
318  WorkQueue = (pvtWorkQueue_t *)wq;
319 
323  xSemaphoreTake(WorkQueue->Lock, portMAX_DELAY);
324 
328  WorkQueue->ExitThread = 1;
329 
333  xSemaphoreGive(WorkQueue->Event);
334 
338  xSemaphoreGive(WorkQueue->Lock);
339 }
340 
341 #endif
342 
343 
345 {
346  /****************************/
347  pvtWorkQueue_t *WorkQueue;
348  pvtWorkItem_t *WorkItem;
349  /****************************/
350 
351  WorkQueue = (pvtWorkQueue_t *)wq;
352 
353  WorkItem = (pvtWorkItem_t *)malloc(sizeof(pvtWorkItem_t));
354  if (WorkItem == NULL) {
355  return pdFAIL;
356  }
357 
358  WorkItem->Function = Function;
359  WorkItem->UserData = UserData;
360 
364  xSemaphoreTake(WorkQueue->Lock, portMAX_DELAY);
365 
369  Enqueue(&WorkQueue->Queue, &WorkItem->Node);
370 
374  xSemaphoreGive(WorkQueue->Event);
375 
379  xSemaphoreGive(WorkQueue->Lock);
380 
381  return pdPASS;
382 }
383 
384 
int QueueWorkItem(WorkQueue_t wq, WorkItem_t Function, void *UserData)
Definition: workqueue.c:344
void Enqueue(Queue_t *Queue, DlNode_t *Node)
Definition: queue_simple.c:54
void DestroyWorkQueue(WorkQueue_t wq)
Definition: workqueue.c:312
SemaphoreHandle_t Event
Definition: workqueue.c:83
SemaphoreHandle_t Lock
Definition: workqueue.c:85
DlNode_t * Dequeue(Queue_t *Queue)
Definition: queue_simple.c:67
#define IsQueueEmpty(_queue)
Definition: queue_simple.h:75
static void WorkerThread(void *parameters)
Definition: workqueue.c:101
TaskHandle_t WorkerThread
Definition: workqueue.c:87
WorkItem_t Function
Definition: workqueue.c:60
struct pvtWorkItem_t_ pvtWorkItem_t
WorkQueue_t CreateWorkQueueEx(const char *const Name, uint16_t StackSize, UBaseType_t Priority)
Definition: workqueue.c:255
Queue_t Queue
Definition: workqueue.c:78
void * WorkQueue_t
Definition: workqueue.h:58
void * UserData
Definition: workqueue.c:65
struct pvtWorkQueue_t_ pvtWorkQueue_t
DlNode_t Node
Definition: workqueue.c:55
void(* WorkItem_t)(void *UserData)
Definition: workqueue.h:52
void InitQueue(Queue_t *Queue)
Definition: queue_simple.c:44
#define CONTAINING_RECORD(_address, _type, _field)
Definition: dlist.h:184