1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions for tasklets and the tasklet scheduler.
32  */
33 
34 #ifndef TASKLET_HPP_
35 #define TASKLET_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <stdio.h>
40 
41 #include <openthread/tasklet.h>
42 
43 #include "common/locator.hpp"
44 #include "common/non_copyable.hpp"
45 
46 namespace ot {
47 
48 /**
49  * @addtogroup core-tasklet
50  *
51  * @brief
52  *   This module includes definitions for tasklets and the tasklet scheduler.
53  *
54  * @{
55  *
56  */
57 
58 /**
59  * Is used to represent a tasklet.
60  *
61  */
62 class Tasklet : public InstanceLocator
63 {
64 public:
65     /**
66      * Implements the tasklet scheduler.
67      *
68      */
69     class Scheduler : private NonCopyable
70     {
71         friend class Tasklet;
72 
73     public:
74         /**
75          * Initializes the object.
76          *
77          */
Scheduler(void)78         Scheduler(void)
79             : mTail(nullptr)
80         {
81         }
82 
83         /**
84          * Indicates whether or not there are tasklets pending.
85          *
86          * @retval TRUE   If there are tasklets pending.
87          * @retval FALSE  If there are no tasklets pending.
88          *
89          */
AreTaskletsPending(void) const90         bool AreTaskletsPending(void) const { return mTail != nullptr; }
91 
92         /**
93          * Processes all tasklets queued when this is called.
94          *
95          */
96         void ProcessQueuedTasklets(void);
97 
98     private:
99         void PostTasklet(Tasklet &aTasklet);
100 
101         Tasklet *mTail; // A circular singly linked-list
102     };
103 
104     /**
105      * Reference is called when the tasklet is run.
106      *
107      * @param[in]  aTasklet  A reference to the tasklet being run.
108      *
109      */
110     typedef void (&Handler)(Tasklet &aTasklet);
111 
112     /**
113      * Creates a tasklet instance.
114      *
115      * @param[in]  aInstance   A reference to the OpenThread instance object.
116      * @param[in]  aHandler    A pointer to a function that is called when the tasklet is run.
117      *
118      */
Tasklet(Instance & aInstance,Handler aHandler)119     Tasklet(Instance &aInstance, Handler aHandler)
120         : InstanceLocator(aInstance)
121         , mHandler(aHandler)
122         , mNext(nullptr)
123     {
124     }
125 
126     /**
127      * Puts the tasklet on the tasklet scheduler run queue.
128      *
129      * If the tasklet is already posted, no change is made and run queue stays as before.
130      *
131      */
132     void Post(void);
133 
134     /**
135      * Indicates whether the tasklet is posted or not.
136      *
137      * @retval TRUE  The tasklet is posted.
138      * @retval FALSE The tasklet is not posted.
139      *
140      */
IsPosted(void) const141     bool IsPosted(void) const { return (mNext != nullptr); }
142 
143 private:
RunTask(void)144     void RunTask(void) { mHandler(*this); }
145 
146     Handler  mHandler;
147     Tasklet *mNext;
148 };
149 
150 /**
151  * Defines a tasklet owned by specific type and using a method on owner type as the callback.
152  *
153  * @tparam Owner              The type of owner of this tasklet.
154  * @tparam HandleTaskletPtr   A pointer to a non-static member method of `Owner` to use as tasklet handler.
155  *
156  * The `Owner` MUST be a type that is accessible using `InstanceLocator::Get<Owner>()`.
157  *
158  */
159 template <typename Owner, void (Owner::*HandleTaskletPtr)(void)> class TaskletIn : public Tasklet
160 {
161 public:
162     /**
163      * Initializes the tasklet.
164      *
165      * @param[in]  aInstance   The OpenThread instance.
166      *
167      */
TaskletIn(Instance & aInstance)168     explicit TaskletIn(Instance &aInstance)
169         : Tasklet(aInstance, HandleTasklet)
170     {
171     }
172 
173 private:
174     static void HandleTasklet(Tasklet &aTasklet); // Implemented in `locator_getters.hpp`
175 };
176 
177 /**
178  * Defines a tasklet that also maintains a user context pointer.
179  *
180  * In typical `Tasklet` use, in the handler callback, the owner of the tasklet is determined using `GetOwner<Type>`
181  * method. This method works if there is a single instance of `Type` within OpenThread instance hierarchy. The
182  * `TaskletContext` is intended for cases where there may be multiple instances of the same class/type using a `Tasklet`
183  * object. `TaskletContext` will store a context `void *` information.
184  *
185  */
186 class TaskletContext : public Tasklet
187 {
188 public:
189     /**
190      * Creates a tasklet instance.
191      *
192      * @param[in]  aInstance   A reference to the OpenThread instance.
193      * @param[in]  aHandler    A pointer to a function that is called when the tasklet is run.
194      * @param[in]  aContext    A pointer to an arbitrary context information.
195      *
196      */
TaskletContext(Instance & aInstance,Handler aHandler,void * aContext)197     TaskletContext(Instance &aInstance, Handler aHandler, void *aContext)
198         : Tasklet(aInstance, aHandler)
199         , mContext(aContext)
200     {
201     }
202 
203     /**
204      * Returns the pointer to the arbitrary context information.
205      *
206      * @returns Pointer to the arbitrary context information.
207      *
208      */
GetContext(void)209     void *GetContext(void) { return mContext; }
210 
211 private:
212     void *mContext;
213 };
214 
215 /**
216  * @}
217  *
218  */
219 
220 } // namespace ot
221 
222 #endif // TASKLET_HPP_
223