Windows: remove trailing whitespace
[openafs.git] / src / WINNT / kfw / inc / netidmgr / kmq.h
1 /*
2  * Copyright (c) 2005 Massachusetts Institute of Technology
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24
25 /* $Id$ */
26
27 #ifndef __KHIMAIRA_KMQ_H__
28 #define __KHIMAIRA_KMQ_H__
29
30 /*! \defgroup kmq NetIDMgr Message Queue */
31 /*@{*/
32
33 #include<khdefs.h>
34 #include<khlist.h>
35 #include<kherr.h>
36
37 /* general */
38 #ifdef _WIN32
39 typedef DWORD kmq_thread_id;
40 typedef DWORD kmq_timer;
41 #endif
42
43 #ifdef _WIN32
44 /*! \brief Window message for kmq
45
46    This message is sent to the window procedure of a window if that
47    window is a subscriber to KMQ messages.
48
49     \see kmq_subscribe_hwnd() for more information about handling this
50         window message
51  */
52 #define KMQ_WM_DISPATCH (WM_APP+0x100)
53 #endif
54
55 /* callback */
56
57 /*! \brief A message callback
58
59     Should return TRUE if the message is properly handled.  Otherwise
60     return FALSE */
61 typedef khm_int32 (KHMAPI *kmq_callback_t)(khm_int32 msg_type,
62                                            khm_int32 msg_sub_type,
63                                            khm_ui_4 uparam,
64                                            void * vparam);
65
66 /* message */
67
68 /*! \brief A single response.
69
70     Certain broadcast messages may user scatter-gather type
71     notification and result gathering.  Individual subscribers to a
72     message attach their individual responses to a ::kmq_response
73     object and attach that to the message which can later be read by
74     the sender of the message.
75  */
76 typedef struct tag_kmq_response {
77     kmq_thread_id thread;
78     void * response;
79
80     LDCL(struct tag_kmq_response);
81 } kmq_response;
82
83 /*! \brief A single message
84  */
85 typedef struct tag_kmq_message {
86     khm_int32 type;             /*!< Type of message */
87     khm_int32 subtype;          /*!< Subtype of message */
88
89     khm_ui_4 uparam;             /*!< Integer parameter */
90     void * vparam;            /*!< Pointer to parameter blob */
91
92     khm_int32 nSent;            /*!< Number of instances of message
93                                   sent (for broadcast messages) */
94
95     khm_int32 nCompleted;       /*!< Number of instances that have
96                                   completed processing (for broadcast
97                                   messages) */
98
99     khm_int32 nFailed;          /*!< Number of instances that failed
100                                   to process (for broadcast
101                                   messages) */
102
103     kmq_response * responses;   /*!< List of responses */
104     HANDLE wait_o;              /*!< Event to wait on (only valid if
105                                   the publisher of the message
106                                   requested a handle to the call) */
107
108     kmq_timer timeSent;         /*!< Time at which the message was
109                                   sent */
110     kmq_timer timeExpire;       /*!< Time at which the message
111                                   expires */
112
113     kherr_context * err_ctx;    /*!< Error context for the message */
114
115     khm_int32 refcount;
116
117     LDCL(struct tag_kmq_message);
118 } kmq_message;
119
120 /*! \brief A handle to a call
121  */
122 typedef kmq_message *kmq_call;
123
124 /*! \brief Message reference */
125 typedef struct tag_kmq_message_ref {
126     kmq_message * msg;          /*!< Message that we are referring
127                                   to */
128     kmq_callback_t recipient;   /*!< The recipient of the message */
129
130     LDCL(struct tag_kmq_message_ref);
131 } kmq_message_ref;
132
133 /*! \brief Message queue
134
135     Each thread gets its own message queue.  When a message is
136     broadcast to which there is a subscriber in a particular thread, a
137     reference to the message is placed in the message queue of the
138     thread.  The dispatch procedure then dispatches the message as
139     described in the message reference.
140 */
141 typedef struct tag_kmq_queue {
142     kmq_thread_id thread;       /*!< The thread id  */
143
144     CRITICAL_SECTION cs;
145     HANDLE wait_o;
146
147     khm_int32 load;             /*!< Number of messages waiting to be
148                                   processed on this message queue.  */
149     kmq_timer last_post;        /*!< Time the last message was
150                                   received */
151
152     khm_int32 flags;            /*!< Flags.  Currently, it's just KMQ_QUEUE_FLAG_DELETED */
153
154     /*Q*/
155     QDCL(kmq_message_ref);      /*!< Queue of message references  */
156
157     /*Lnode*/
158     LDCL(struct tag_kmq_queue);
159 } kmq_queue;
160
161 #define KMQ_QUEUE_FLAG_DELETED 0x0008
162
163 /*! \brief Message subscription
164
165     A subscription binds a recipient with a message type.  These are
166     specific to a thread. I.e. a subscription that was made in one
167     thread will not receive messages in the context of another thread.
168 */
169 typedef struct tag_kmq_msg_subscription {
170     khm_int32 magic;            /*!< Magic number.  Should always be
171                                   ::KMQ_MSG_SUB_MAGIC */
172     khm_int32 type;             /*!< Type of message */
173     khm_int32 rcpt_type;        /*!< Type of recipient.  One of
174                                   ::KMQ_RCPTTYPE_CB or
175                                   ::KMQ_RCPTTYPE_HWND  */
176     union {
177         kmq_callback_t cb;      /*!< Callback if the subscription is
178                                   of callback type */
179         HWND hwnd;              /*!< Window handle if the subscription
180                                   is a windows message type */
181     } recipient;
182
183     kmq_queue * queue;          /*!< Associated queue */
184
185     /*lnode*/
186     LDCL(struct tag_kmq_msg_subscription);
187 } kmq_msg_subscription;
188
189 #define KMQ_MSG_SUB_MAGIC 0x3821b58e
190
191 /*! \brief Callback recipient type
192
193     The recipient is a callback function */
194 #define KMQ_RCPTTYPE_CB     1
195
196 /*! \brief Windows recipient type
197
198     The recipient is a window */
199 #define KMQ_RCPTTYPE_HWND   2
200
201 /* publishers */
202
203 /*! \brief A completion handler for a message
204
205     Each message type can have a completion handler.  Once a message
206     of this a specific type has been broadcast and handled by all the
207     subscripbers, the message will be passed down to the completion
208     handler before the associated data structures are freed.  This
209     allows applications that define message type to also define clean
210     up for each message.  For example, the completion handler can
211     initiate another message if the messages form a sequence or free
212     up blocks of memory that was passed as the parameter to the
213     message.
214  */
215 typedef void (KHMAPI *kmq_msg_completion_handler)(kmq_message *);
216
217 /*! \brief A message type
218  */
219 typedef struct tag_kmq_msg_type {
220     khm_int32 id;               /*!< Identifier for the message
221                                   type. */
222     kmq_msg_subscription * subs; /*!< The list of subscriptions */
223     kmq_msg_completion_handler completion_handler; /*!< Completion
224                                   handler for the message type */
225
226     wchar_t * name;             /*!< Name of the message type for
227                                   named types.  Message type names are
228                                   language independant. */
229
230     /*Lnode*/
231     LDCL(struct tag_kmq_msg_type);
232 } kmq_msg_type;
233
234 /*! \brief The maximum number of message types
235  */
236 #define KMQ_MSG_TYPE_MAX 255
237
238 /*! \brief Maximum number of characters in a message type name
239
240     The count includes the terminating NULL
241  */
242 #define KMQ_MAXCCH_TYPE_NAME 256
243
244 /*! \brief Maximum number of bytes in a message type name
245
246     Type count includes the terminating NULL
247  */
248 #define KMQ_MAXCB_TYPE_NAME (KMQ_MAXCCH_TYPE_NAME * sizeof(wchar_t))
249
250 KHMEXP khm_int32 KHMAPI kmq_init(void);
251
252 KHMEXP khm_int32 KHMAPI kmq_exit(void);
253
254 /*! \brief Register a message type
255
256     Registers a custom message type.  The \a name parameter specifies
257     a language independent name for the message type and must be
258     unique and must be less than ::KMQ_MAXCCH_TYPE_NAME characters.
259
260     \param[in] name Name of the message type.  Upto
261         ::KMQ_MAXCCH_TYPE_NAME characters including terminating NULL.
262         The \a name cannot be a zero length string.
263
264     \param[out] new_id Receives the new message type ID.  Specify NULL
265         if the new message type is not required.
266
267     \see kmq_find_type() and kmq_unregister_type()
268
269     \retval KHM_ERROR_INVALID_PARAM The \a name parameter was invalid.
270     \retval KHM_ERROR_EXISTS A message type with that name already exists.
271     \retval KHM_ERROR_NO_RESOURCES Can't register any more message types.
272     \retval KHM_ERROR_SUCCESS The operation succeeded.
273  */
274 KHMEXP khm_int32 KHMAPI kmq_register_type(wchar_t * name, khm_int32 * new_id);
275
276 /*! \brief Find a message type
277
278     Find the message type with the given name.  If found, the type ID
279     is returned in \a id.
280
281     \retval KHM_ERROR_SUCCESS A message type with the given name was
282         found.
283     \retval KHM_ERROR_NOT_FOUND A message type with the given name was
284         not found.
285  */
286 KHMEXP khm_int32 KHMAPI kmq_find_type(wchar_t * name, khm_int32 * id);
287
288 /*! \brief Unregister a message type
289
290     Unregisters a message type that was registered using
291     kmq_register_type().
292
293     \retval KHM_ERROR_SUCCESS The specified message type was
294         successfully unregistered.
295
296     \retval KHM_ERROR_NOT_FOUND The message type was not found.
297  */
298 KHMEXP khm_int32 KHMAPI kmq_unregister_type(khm_int32 id);
299
300 /*! \brief Subscribte to a message type.
301
302     Adds a subscription to messages of type \a type.  Subscriptions
303     are managed per thread.  Therefore the subscription is actually
304     added to the subscription list for the current thread (the thread
305     which calls kmq_subscribe()).
306
307     When a message of type \a type is received by the thread, it is
308     dispatched to the callback function identified by \a cb within the
309     context of this thread.
310
311     \note Calling kmq_subscribe() from within multiple threads with
312         the same \a type and \a cb will result in multiple
313         subscriptions.
314
315     \see kmq_unsubscribe()
316     \see kmq_dispatch()
317 */
318 KHMEXP khm_int32 KHMAPI kmq_subscribe(khm_int32 type, kmq_callback_t cb);
319
320 /*! \brief Subscribe a window to a message type
321
322     Adds the window specified by \a hwnd to the subscription list for
323     the message type \a type.  When a message of this type is posted,
324     then the window procedure of the window \a hwnd receives a message
325     ::KMQ_WM_DISPATCH.
326
327     When a window receives a ::KMQ_WM_DISPATCH message, it means that
328     a message has been posted which is of a type that the window has
329     subscribed for.  Because of the way Windows handles window
330     messages and the way NetIDMgr message queues work, a thread which
331     has a window (or thread) procedure can not call kmq_dispatch() to
332     handle these messages.  For threads that have window or thread
333     message loops, they must call kmq_subscribe_hwnd() to subscribe a
334     particular window (for thread message loops, this would be the
335     HWND of the message window for the thread) to NetIDMgr messages.
336
337     There are two supported ways of handling the ::KMQ_WM_DISPATCH
338     message.  Examples of both are provided below.
339
340     Handling the message inline:
341
342     \code
343     LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
344     kmq_message * m;
345     khm_int32 rv;
346     ...
347     switch(uMsg) {
348     case WM_CREATE:
349        ...
350        kmq_subscribe_hwnd(KMSG_CRED, hwnd);
351        ...
352        break;
353
354     case WM_DESTROY:
355        ...
356        kmq_unsubscribe_hwnd(KMSG_CRED, hwnd);
357        ...
358        break;
359
360     ...
361     case KMQ_WM_DISPATCH:
362         kmq_wm_begin(lParam,&m);
363
364         if(m->type == KMSG_CRED && m->subtype == KMSG_CRED_ROOTDELTA) {
365         // do something
366         rv = KHM_ERROR_SUCCESS;
367         }
368
369         return kmq_wm_end(m, rv);
370     ...
371     };
372     ...
373     }
374     \endcode
375
376     The other method is to dispatch the ::KMQ_WM_DISPATCH message to a
377     secondary callback function:
378
379     \code
380     khm_int32 msg_handler(khm_int32 t, khm_int32 st, khm_ui_4 up, void * pb) {
381         khm_int32 rv = KHM_ERROR_SUCCESS;
382
383         //handle message
384
385         return rv;
386     }
387
388     LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
389     kmq_message * m;
390     khm_int32 rv;
391     ...
392     switch(uMsg) {
393     ...
394
395     case WM_CREATE:
396        ...
397        kmq_subscribe_hwnd(KMSG_CRED, hwnd);
398        ...
399        break;
400
401     case WM_DESTROY:
402        ...
403        kmq_unsubscribe_hwnd(KMSG_CRED, hwnd);
404        ...
405        break;
406
407     ...
408     case KMQ_WM_DISPATCH:
409         return kmq_wm_dispatch(lParam, msg_handler);
410     ...
411     };
412     ...
413     }
414     \endcode
415
416     \note Make sure you unsubscribe from the message type when the
417         window is destroyed.
418
419     \see kmq_unsubscribe_hwnd()
420     \see kmq_wm_begin()
421     \see kmq_wm_end()
422     \see kmq_wm_dispatch()
423  */
424 KHMEXP khm_int32 KHMAPI kmq_subscribe_hwnd(khm_int32 type, HWND hwnd);
425
426 #ifdef _WIN32
427 /*! \brief Begins handling a KMQ_WM_DISPATCH message
428
429     \return The return value of this function should be ignored.
430
431     \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH
432  */
433 KHMEXP LRESULT KHMAPI kmq_wm_begin(LPARAM lparm, kmq_message ** m);
434
435 /*! \brief Ends handling a KMQ_WM_DISPATCH message
436
437     \return The return value of this function should be the return
438         value of the window procedure.  See kmq_subscribe_hwnd()
439         documentation for example
440
441     \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH
442  */
443 KHMEXP LRESULT KHMAPI kmq_wm_end(kmq_message *m, khm_int32 rv);
444
445 /*! \brief Dispatches a KMQ_WM_DISPATCH message to a callback
446
447     \return The return value of this function should be the return
448         value of the window procedure.  See kmq_subscribe_hwnd()
449         documentation for example.
450
451     \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH
452  */
453 KHMEXP LRESULT KHMAPI kmq_wm_dispatch(LPARAM lparm, kmq_callback_t cb);
454 #endif
455
456 /*! \brief Unsubscribe a callback from a message type
457
458     Removes the subscription for message type \a type for callback
459     function \a cb from the subscription list for the current thread
460     (the thread that calls kmq_unsubscribe()).
461
462     \note kmq_unsubscribe() can only remove subscriptions for the subscription
463         list for the current thread.
464
465     \see kmq_subscribe()
466     \see kmq_dispatch()
467 */
468 KHMEXP khm_int32 KHMAPI kmq_unsubscribe(khm_int32 type, kmq_callback_t cb);
469
470 /*! \brief Unsubscribe a window from a message type
471
472     Removes the specific window from the subsription list for message
473     type \a type.
474
475     \see kmq_subscribe_hwnd()
476 */
477 KHMEXP khm_int32 KHMAPI kmq_unsubscribe_hwnd(khm_int32 type, HWND hwnd);
478
479 /*! \brief Create an ad-hoc subscription
480
481     An ad-hoc subscription describes a callback point in a thread that
482     can be dispatched messages to individually without broadcasting.
483
484     \see kmq_post_sub_msg(), kmq_post_sub_msg_ex(),
485         kmq_send_sub_msg(), kmq_post_subs_msg(),
486         kmq_post_subs_msg_ex(), kmq_send_subs_msg(),
487         kmq_delete_subscription()
488 */
489 KHMEXP khm_int32 KHMAPI kmq_create_subscription(
490     kmq_callback_t cb,
491     khm_handle * result);
492
493 /*! \brief Create an ad-hoc subscription for a window
494
495     An ad-hoc subscription describes a window that will be dispatched
496     messages individually without broadcasting.
497
498     \see kmq_post_sub_msg(), kmq_post_sub_msg_ex(),
499         kmq_send_sub_msg(), kmq_post_subs_msg(),
500         kmq_post_subs_msg_ex(), kmq_send_subs_msg(),
501         kmq_delete_subscription()
502  */
503 KHMEXP khm_int32 KHMAPI kmq_create_hwnd_subscription(HWND hw,
504                                                      khm_handle * result);
505
506 /*! \brief Delete an ad-hoc subscription
507
508     Deletes a subscriptoin that was created using
509     kmq_create_subscription()
510  */
511 KHMEXP khm_int32 KHMAPI kmq_delete_subscription(khm_handle sub);
512
513 /*! \brief Post a message to a subscription
514
515     Equivalent of kmq_post_msg() but only posts the message to the
516     specified subscription.
517  */
518 KHMEXP khm_int32 KHMAPI kmq_post_sub_msg(
519     khm_handle sub,
520     khm_int32 type,
521     khm_int32 subtype,
522     khm_ui_4 uparam,
523     void * vparam);
524
525 /*! \brief Post a message to a subscription and acquire a handle to the call
526  */
527 KHMEXP khm_int32 KHMAPI kmq_post_sub_msg_ex(
528     khm_handle sub,
529     khm_int32 type,
530     khm_int32 subtype,
531     khm_ui_4 uparam,
532     void * vparam,
533     kmq_call * call);
534
535 /*! \brief Send a synchronous message to a subscription
536
537     \retval KHM_ERROR_SUCCESS The call succeeded, and no subscribers reported errors
538     \retval KHM_ERROR_PARTIAL The call succeeded, but at least one subscriber reported errors
539  */
540 KHMEXP khm_int32 KHMAPI kmq_send_sub_msg(
541     khm_handle sub,
542     khm_int32 type,
543     khm_int32 subtype,
544     khm_ui_4 uparam,
545     void * vparam);
546
547 /*! \brief Post a message to a group of subscriptions
548
549     The block of memory pointed to by \a subs should be an array of
550     subscriptions.  The number of elements in that array should be \a
551     n_subs.  A message as specified by the remaining parameters will
552     be dispatched to all of the subscription points in the array.
553  */
554 KHMEXP khm_int32 KHMAPI kmq_post_subs_msg(
555     khm_handle * subs,
556     khm_size  n_subs,
557     khm_int32 type,
558     khm_int32 subtype,
559     khm_ui_4 uparam,
560     void * vparam);
561
562 /*! \brief Post a message to a group of subscriptions and acquire a handle to the call
563
564     The block of memory pointed to by \a subs should be an array of
565     subscriptions.  The number of elements in that array should be \a
566     n_subs.  A message as specified by the remaining parameters will
567     be dispatched to all of the subscription points in the array, and
568     a handle to the call will be returned in \a call.
569
570     The returned \a call will reference all of the dispatches that
571     were made.
572 */
573 KHMEXP khm_int32 KHMAPI kmq_post_subs_msg_ex(
574     khm_handle * subs,
575     khm_int32 n_subs,
576     khm_int32 type,
577     khm_int32 subtype,
578     khm_ui_4 uparam,
579     void * vparam,
580     kmq_call * call);
581
582 /*! \brief Send a synchronous message to a group of subscriptions
583
584     The block of memory pointed to by \a subs should be an array of
585     subscriptions.  The number of elements in that array should be \a
586     n_subs.  A message as specified by the remaining parameters will
587     be dispatched to all of the subscription points in the array.  The
588     function will not return until all of the calls have succeeded.
589
590     \retval KHM_ERROR_SUCCESS The call succeeded, and no subscribers reported errors
591     \retval KHM_ERROR_PARTIAL The call succeeded, but at least one subscriber reported errors
592 */
593 KHMEXP khm_int32 KHMAPI kmq_send_subs_msg(
594     khm_handle *subs,
595     khm_int32 n_subs,
596     khm_int32 type,
597     khm_int32 subtype,
598     khm_ui_4 uparam,
599     void * vparam);
600
601 /*! \brief Dispatch a message for the current thread.
602
603     This function opens the message list for the current thread and
604     dispatches the first message instance that is found.  Note that if
605     multiple callbacks subscribe to the same message type in the same
606     thread, then when a message of that type is received, multiple
607     message instances are added to the message queue corresponding to
608     each subscription.
609
610     If no message instances are waiting in the queue, kmq_dispatch()
611     waits for the \a timeout period for a message.
612
613     \param[in] timeout The timeout period in milliseconds.  Specify INFINITE for
614         kmq_dispatch() to wait indefinitely.
615
616     \retval KHM_ERROR_SUCCESS A message instance was dispatched
617     \retval KHM_ERROR_TIMEOUT The timeout period elapsed
618     \retval KHM_ERROR_EXIT The message found on the queue was <KMSG_SYSTEM,KMSG_SYSTEM_EXIT>
619 */
620 KHMEXP khm_int32 KHMAPI kmq_dispatch(kmq_timer timeout);
621
622 /*! \brief Send a message
623
624     The specified message will be posted to all the subscribers of the
625     message type.  Then the function will wait for all the subscribers
626     to finish processing the message before returning.
627
628     \param[in] type The type of the message
629     \param[in] subtype The subtype
630     \param[in] uparam The khm_ui_4 parameter for the message
631     \param[in] blob The parameter blob for the message
632
633     \note The internal timeout for this function is INFINITE.  If you
634         it is desirable to use a different timeout, use
635         kmq_post_message_ex() and kmq_wait() functions.
636
637     \retval KHM_ERROR_SUCCESS The call succeeded and no subscribers returned errors
638     \retval KHM_ERROR_PARTIAL The call succeeded but at least one subscriber returned an error
639 */
640 KHMEXP khm_int32 KHMAPI kmq_send_message(
641     khm_int32 type,
642     khm_int32 subtype,
643     khm_ui_4 uparam,
644     void * blob);
645
646 /*! \brief Post a message
647
648     The specified message will be posted to all the subscribers of the
649     message type.  The function returns immediately.
650
651     If you want to be able to wait for all the subscribers to finish
652     processing the message, you should use kmq_post_message_ex()
653     instead.
654
655     \param[in] type The type of the message
656     \param[in] subtype The subtype
657     \param[in] uparam The khm_ui_4 parameter for the message
658     \param[in] blob The parameter blob for the message
659 */
660 KHMEXP khm_int32 KHMAPI kmq_post_message(
661     khm_int32 type,
662     khm_int32 subtype,
663     khm_ui_4 uparam,
664     void * blob);
665
666 /*! \brief Post a message and acquire a handle to the call.
667
668     The specified message is posted to all the subscribers.  In
669     addition, a handle is obtained for the call which can be used in
670     subsequent call to kmq_free_call() or kmq_wait().
671
672     Call kmq_free_call() to free the handle.
673
674     \param[in] type The type of the message
675     \param[in] subtype The subtype
676     \param[in] uparam The khm_ui_4 parameter for the message
677     \param[in] blob The parameter blob for the message
678     \param[out] call Receives the call handle.  Set to NULL if the call handle is not required.
679
680     \see kmq_free_call()
681 */
682 KHMEXP khm_int32 KHMAPI kmq_post_message_ex(
683     khm_int32 type,
684     khm_int32 subtype,
685     khm_ui_4 uparam,
686     void * blob,
687     kmq_call * call);
688
689 /*! \brief Free a handle to a call obtained through kmq_post_message_ex()
690
691     All call handles obtained through kmq_post_message_ex() must be
692     freed via a call to kmq_free_call().
693 */
694 KHMEXP khm_int32 KHMAPI kmq_free_call(kmq_call call);
695
696 /*! \brief Sends a <KMSG_SYSTEM,KMSG_SYSTEM_EXIT> message to the specified thread.
697
698     The message itself will not be received by any callback function,
699     however, any kmq_dispatch() function that is currently active of
700     becomes active will exit with a KHM_ERROR_EXIT code.
701     kmq_send_thread_quit_message() will wait for this to happen before
702     returning.
703     */
704 KHMEXP khm_int32 KHMAPI kmq_send_thread_quit_message(
705     kmq_thread_id thread,
706     khm_ui_4 uparam);
707
708 /*! \brief Post a <KMSG_SYSTEM,KMSG_SYSTEM_EXIT> message to the specified thread.
709
710     The message itself will not be received by any callback function,
711     however, any kmq_dispatch() function that is currently active of
712     becomes active will exit with a KHM_ERROR_EXIT code.
713     kmq_post_thread_quit_message() will return immediately.
714     */
715 KHMEXP khm_int32 KHMAPI kmq_post_thread_quit_message(
716     kmq_thread_id thread,
717     khm_ui_4 uparam,
718     kmq_call * call);
719
720 KHMEXP khm_int32 KHMAPI kmq_get_next_response(kmq_call call, void ** resp);
721
722 /*! \brief Check if a specific call has completed
723
724     \return TRUE if the call has completed. FALSE otherwise.
725 */
726 KHMEXP khm_boolean KHMAPI kmq_has_completed(kmq_call call);
727
728 /*! \brief Wait for a call to complete.
729
730     Waits for the specified call to complete.  If the call dispatched
731     to multiple recipients, the function waits for all dispatches to
732     complete.
733
734     If the call has already completed, then the function returns
735     immediately.
736
737     If more than one thread is waiting for a single message to
738     complete, then only one of them will be released when the message
739     compeltes.  Each subsequent thread will be released as each
740     released thread calls kmq_free_call().
741
742     \param[in] call A handle to a call.
743     \param[in] timeout Specifies, in milliseconds, the amount of time
744         to wait for the call to complete. Specify INFINITE to wait
745         indefinitely.
746
747     \retval KHM_ERROR_SUCCESS The call completed
748     \retval KHM_ERROR_TIMEOUT The timeout period expired
749     \retval KHM_ERROR_INVALID_PARAM One of the parameters were invalid.
750 */
751 KHMEXP khm_int32 KHMAPI kmq_wait(kmq_call call, kmq_timer timeout);
752
753 /*! \brief Sets the completion handler for a specified message type.
754
755     \note Only one completion handler can exist for one message type.
756         Calling this function overwrites the previous completion
757         handler.
758 */
759 KHMEXP khm_int32 KHMAPI kmq_set_completion_handler(
760     khm_int32 type,
761     kmq_msg_completion_handler hander);
762
763 /*@}*/
764 #endif