1 /*
2 
3   silcasync.h
4 
5   Author: Pekka Riikonen <priikone@silcnet.org>
6 
7   Copyright (C) 2005 - 2007 Pekka Riikonen
8 
9   The contents of this file are subject to one of the Licenses specified
10   in the COPYING file;  You may not use this file except in compliance
11   with the License.
12 
13   The software distributed under the License is distributed on an "AS IS"
14   basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15   KIND, either expressed or implied.  See the COPYING file for more
16   information.
17 
18 */
19 
20 /****h* silcutil/SILC Async Operation Interface
21  *
22  * DESCRIPTION
23  *
24  * SILC Async Operation API is an interface that can be used to control
25  * asynchronous operations.  All functions that take callback as argument
26  * should return SilcAsyncOperation context.  That context then can be
27  * used to control, such as, abort the asynchronous operation.  Using
28  * SILC Async Operation API, asynchronous functions can be controlled
29  * and aborted safely.
30  *
31  * The SILC Async Operation API is divided in two levels; the underlaying
32  * operation level that implements the asynchronous operation, and the
33  * upper layer that can control the asynchronous operation.  The operation
34  * layer must guarantee that if the upper layer aborts the asynchronous
35  * operation, no callback function will be called back to the upper layer.
36  * This must be remembered when implementing the operation layer.
37  *
38  ***/
39 
40 #ifndef SILCASYNC_H
41 #define SILCASYNC_H
42 
43 /****s* silcutil/SilcAsyncOperationAPI/SilcAsyncOperation
44  *
45  * NAME
46  *
47  *    typedef struct SilcAsyncOperationObject *SilcAsyncOperation;
48  *
49  * DESCRIPTION
50  *
51  *    The asynchronous operation context allocated by silc_async_alloc.
52  *    The layer that implements the asynchronous operation allocates this
53  *    context.  The layer that receives this context can use it to control
54  *    the underlaying asynchronous operation.  It is also possible to use
55  *    a pre-allocated context by using SilcAsyncOperationStruct instead
56  *    SilcAsyncOperation.
57  *
58  ***/
59 typedef struct SilcAsyncOperationObject *SilcAsyncOperation;
60 
61 /****s* silcutil/SilcAsyncOperationAPI/SilcAsyncOperationStruct
62  *
63  * NAME
64  *
65  *    typedef struct SilcAsyncOperationObject SilcAsyncOperationStruct;
66  *
67  * DESCRIPTION
68  *
69  *    The asynchronous operation context that can be used as a pre-allocated
70  *    context.  This is initialized with silc_async_init.  It need not
71  *    be uninitialized.  The layer that implements the asynchronous
72  *    operation initializes this context.  The layer that has access to this
73  *    context can use it to control the underlaying asynchronous operation.
74  *
75  ***/
76 typedef struct SilcAsyncOperationObject SilcAsyncOperationStruct;
77 
78 /****f* silcutil/SilcAsyncOperationAPI/SilcAsyncOperationAbort
79  *
80  * SYNOPSIS
81  *
82  *    typedef void (*SilcAsyncOperationAbort)(SilcAsyncOperation op,
83  *                                            void *context);
84  *
85  * DESCRIPTION
86  *
87  *    This callback is called when upper layer calls the silc_async_abort,
88  *    and is used to actually perform the abortion of the asynchronous
89  *    operation.  The silc_async_free must not be called in this function.
90  *
91  *    This callback type can also be provided to silc_async_abort function
92  *    by the upper layer, if it wants that callback is called to the upper
93  *    layer when aborting the operation.
94  *
95  ***/
96 typedef void (*SilcAsyncOperationAbort)(SilcAsyncOperation op,
97 					void *context);
98 
99 /****f* silcutil/SilcAsyncOperationAPI/SilcAsyncOperationPause
100  *
101  * SYNOPSIS
102  *
103  *    typedef SilcBool (*SilcAsyncOperationPause)(SilcAsyncOperation op,
104  *                                                SilcBool pause_operation,
105  *                                                void *context);
106  *
107  * DESCRIPTION
108  *
109  *    This callback is used to halt an operation, if upper layer calls the
110  *    silc_async_halt function, or to resume an operation if upper layer
111  *    calls the silc_async_resume, after it has earlier halted the operation.
112  *    If this callback is implemented it is guaranteed that the asynchronous
113  *    operation is not progressed when it is halted.  If the `pause_operation'
114  *    is TRUE the operation is halted.  If it is FALSE, then the operation
115  *    resumes its execution.  This function returns TRUE if the operation
116  *    was (or is going to be) halted or resumed, and FALSE on error.
117  *
118  ***/
119 typedef SilcBool (*SilcAsyncOperationPause)(SilcAsyncOperation op,
120 					    SilcBool pause_operation,
121 					    void *context);
122 
123 /* Upper layer functions for managing asynchronous operations.  Layer
124    that has received SilcAsyncOperation context can control the async
125    operation with these functions. */
126 
127 /****f* silcutil/SilcAsyncOperationAPI/silc_async_halt
128  *
129  * SYNOPSIS
130  *
131  *    SilcBool silc_async_halt(SilcAsyncOperation op);
132  *
133  * DESCRIPTION
134  *
135  *    Halt the execution of the asynchronous operation.  If the operation
136  *    supports this feature, it is guaranteed that the operation is halted
137  *    and its execution is not progressed until the silc_async_resume function
138  *    is called.  The operation still can be aborted even if it is halted.
139  *    If this function is not supported, calling this has no effect and the
140  *    function returns FALSE.  This function is for the upper layer that
141  *    controls the asynchronous operation.
142  *
143  ***/
144 SilcBool silc_async_halt(SilcAsyncOperation op);
145 
146 /****f* silcutil/SilcAsyncOperationAPI/silc_async_resume
147  *
148  * SYNOPSIS
149  *
150  *    SilcBool silc_async_resume(SilcAsyncOperation op);
151  *
152  * DESCRIPTION
153  *
154  *    Resume the execution of the asynchronous operation.  If the halting of
155  *    the operation was supported, then this function is used to resume the
156  *    execution of the operation after it was halted.  If this function is
157  *    not supported, calling this has no effect and the function returns
158  *    FALSE.  This function is for the upper layer that controls the
159  *    asynchronous operation.
160  *
161  ***/
162 SilcBool silc_async_resume(SilcAsyncOperation op);
163 
164 /****f* silcutil/SilcAsyncOperationAPI/silc_async_abort
165  *
166  * SYNOPSIS
167  *
168  *    void silc_async_abort(SilcAsyncOperation op,
169  *                          SilcAsyncOperationAbort abort_cb, void *context);
170  *
171  * DESCRIPTION
172  *
173  *    This function is used by upper layer that received SilcAsyncOperation
174  *    context from an asynchronous function, to abort the asynchronous
175  *    operation.  The `op' becomes invalid after this function returns.
176  *    It is also guaranteed (assuming the use of this API is implemented
177  *    correctly) that some other completion callback is not called after
178  *    the operation was aborted.  However, if the caller wants to receive
179  *    a callback when aborting the caller may specify the `abort_cb' and
180  *    `context' which will be called after the operation is aborted, but
181  *    before the `op' becomes invalid.  The `abort_cb' is called immediately
182  *    inside this function.
183  *
184  ***/
185 void silc_async_abort(SilcAsyncOperation op,
186                       SilcAsyncOperationAbort abort_cb, void *context);
187 
188 /* The operation layer functions.  The layer that performs the async
189    operation use these functions. */
190 
191 /****f* silcutil/SilcAsyncOperationAPI/silc_async_alloc
192  *
193  * SYNOPSIS
194  *
195  *    SilcAsyncOperation silc_async_alloc(SilcAsyncOperationAbort abort_cb,
196  *                                        SilcAsyncOperationPause pause_cb,
197  *                                        void *context);
198  *
199  * DESCRIPTION
200  *
201  *    Start asynchronous operation, and assign `abort_cb' callback for it,
202  *    which can be used by some upper layer to abort the asynchronous
203  *    operation, by calling the silc_async_abort.  The layer which calls
204  *    this function must also call silc_async_free when the asynchronous
205  *    operation is successfully completed.  If it is aborted by upper layer
206  *    then silc_async_free must not be called, since it is called by the
207  *    silc_async_abort function.
208  *
209  *    If the `pause_cb' is provided then the upper layer may also halt and
210  *    then later resume the execution of the operation, by calling the
211  *    silc_async_halt and silc_async_resume respectively.  If `pause_cb' is
212  *    not provided then these functions has no effect for this operation.
213  *
214  * EXAMPLE
215  *
216  *    SilcAsyncOperation silc_async_call(Callback callback, void *cb_context)
217  *    {
218  *      SilcAsyncOperation op;
219  *      ...
220  *
221  *      // Allocate async operation so that caller can control us, like abort
222  *      op = silc_async_alloc(silc_async_call_abort, NULL, ctx);
223  *
224  *      // Start async operation in FSM
225  *      silc_fsm_init(&ctx->fsm, ctx, fsm_destructor, ctx, schedule);
226  *      silc_fsm_start(&ctx->fsm, first_state);
227  *      ...
228  *
229  *      // Return async operation for upper layer
230  *      return op;
231  *    }
232  *
233  ***/
234 SilcAsyncOperation silc_async_alloc(SilcAsyncOperationAbort abort_cb,
235 				    SilcAsyncOperationPause pause_cb,
236 				    void *context);
237 
238 /****f* silcutil/SilcAsyncOperationAPI/silc_async_init
239  *
240  * SYNOPSIS
241  *
242  *    SilcBool silc_async_init(SilcAsyncOperation op,
243  *                             SilcAsyncOperationAbort abort_cb,
244  *                             SilcAsyncOperationPause pause_cb,
245  *                             void *context);
246  *
247  * DESCRIPTION
248  *
249  *    Initializes and starts a pre-allocated asynchronous operation context,
250  *    and assigns `abort_cb' callback for it, which can be used by some upper
251  *    layer to abort the asynchronous operation, by calling the
252  *    silc_async_abort.  Since this use pre-allocated context, the function
253  *    silc_async_free need not be called.  This function is equivalent
254  *    to silc_async_alloc except this does not allocate any memory.  The `op'
255  *    needs not be uninitialized.
256  *
257  *    If the `pause_cb' is provided then the upper layer may also halt and
258  *    then later resume the execution of the operation, by calling the
259  *    silc_async_halt and silc_async_resume respectively.  If `pause_cb' is
260  *    not provided then these functions has no effect for this operation.
261  *
262  ***/
263 SilcBool silc_async_init(SilcAsyncOperation op,
264 			 SilcAsyncOperationAbort abort_cb,
265 			 SilcAsyncOperationPause pause_cb,
266 			 void *context);
267 
268 /****f* silcutil/SilcAsyncOperationAPI/silc_async_free
269  *
270  * SYNOPSIS
271  *
272  *    void silc_async_free(SilcAsyncOperation op);
273  *
274  * DESCRIPTION
275  *
276  *    Stop the asynchronous operation.  If the asynchronous operation ended
277  *    normally (ie. it was not aborted) this function must be called by the
278  *    caller who called silc_async_alloc.  The `op' will become invalid after
279  *    this and the upper layer must not call silc_async_abort after this
280  *    function is called.  The layer that calls this, must call some other
281  *    completion callback to the upper layer, so that it knows that the
282  *    asynchronous operation is completed.
283  *
284  ***/
285 void silc_async_free(SilcAsyncOperation op);
286 
287 /****f* silcutil/SilcAsyncOperationAPI/silc_async_get_context
288  *
289  * SYNOPSIS
290  *
291  *    void *silc_async_get_context(SilcAsyncOperation op);
292  *
293  * DESCRIPTION
294  *
295  *    Returns the context that was given to the silc_async_alloc or
296  *    silc_async_init.
297  *
298  ***/
299 void *silc_async_get_context(SilcAsyncOperation op);
300 
301 #include "silcasync_i.h"
302 
303 #endif /* SILCASYNC_H */
304