2 * Server-side message queues
4 * Copyright (C) 2000 Alexandre Julliard
22 struct message_result
*send_next
; /* next in sender list */
23 struct message_result
*recv_next
; /* next in receiver list */
24 struct msg_queue
*sender
; /* sender queue */
25 struct msg_queue
*receiver
; /* receiver queue */
26 int replied
; /* has it been replied to? */
27 unsigned int result
; /* reply result */
28 unsigned int error
; /* error code to pass back to sender */
33 struct message
*next
; /* next message in list */
34 struct message
*prev
; /* prev message in list */
35 int type
; /* message type (FIXME) */
36 handle_t win
; /* window handle */
37 unsigned int msg
; /* message code */
38 unsigned int wparam
; /* parameters */
39 unsigned int lparam
; /* parameters */
40 unsigned short x
; /* x position */
41 unsigned short y
; /* y position */
42 unsigned int time
; /* message time */
43 unsigned int info
; /* extra info */
44 struct message_result
*result
; /* result in sender queue */
49 struct message
*first
; /* head of list */
50 struct message
*last
; /* tail of list */
55 struct timer
*next
; /* next timer in list */
56 struct timer
*prev
; /* prev timer in list */
57 struct timeval when
; /* next expiration */
58 unsigned int rate
; /* timer rate in ms */
59 handle_t win
; /* window handle */
60 unsigned int msg
; /* message to post */
61 unsigned int id
; /* timer id */
62 unsigned int lparam
; /* lparam for message */
67 struct object obj
; /* object header */
68 unsigned int wake_bits
; /* wakeup bits */
69 unsigned int wake_mask
; /* wakeup mask */
70 unsigned int changed_bits
; /* changed wakeup bits */
71 unsigned int changed_mask
; /* changed wakeup mask */
72 int paint_count
; /* pending paint messages count */
73 struct message_list msg_list
[NB_MSG_KINDS
]; /* lists of messages */
74 struct message_result
*send_result
; /* stack of sent messages waiting for result */
75 struct message_result
*recv_result
; /* stack of received messages waiting for result */
76 struct timer
*first_timer
; /* head of timer list */
77 struct timer
*last_timer
; /* tail of timer list */
78 struct timer
*next_timer
; /* next timer to expire */
79 struct timeout_user
*timeout
; /* timeout for next timer to expire */
82 static void msg_queue_dump( struct object
*obj
, int verbose
);
83 static int msg_queue_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
84 static void msg_queue_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
85 static int msg_queue_signaled( struct object
*obj
, struct thread
*thread
);
86 static int msg_queue_satisfied( struct object
*obj
, struct thread
*thread
);
87 static void msg_queue_destroy( struct object
*obj
);
88 static void timer_callback( void *private );
90 static const struct object_ops msg_queue_ops
=
92 sizeof(struct msg_queue
), /* size */
93 msg_queue_dump
, /* dump */
94 msg_queue_add_queue
, /* add_queue */
95 msg_queue_remove_queue
, /* remove_queue */
96 msg_queue_signaled
, /* signaled */
97 msg_queue_satisfied
, /* satisfied */
98 NULL
, /* get_poll_events */
99 NULL
, /* poll_event */
100 no_get_fd
, /* get_fd */
101 no_flush
, /* flush */
102 no_get_file_info
, /* get_file_info */
103 msg_queue_destroy
/* destroy */
107 static struct msg_queue
*create_msg_queue( struct thread
*thread
)
109 struct msg_queue
*queue
;
112 if ((queue
= alloc_object( &msg_queue_ops
, -1 )))
114 queue
->wake_bits
= 0;
115 queue
->wake_mask
= 0;
116 queue
->changed_bits
= 0;
117 queue
->changed_mask
= 0;
118 queue
->paint_count
= 0;
119 queue
->send_result
= NULL
;
120 queue
->recv_result
= NULL
;
121 queue
->first_timer
= NULL
;
122 queue
->last_timer
= NULL
;
123 queue
->next_timer
= NULL
;
124 queue
->timeout
= NULL
;
125 for (i
= 0; i
< NB_MSG_KINDS
; i
++)
126 queue
->msg_list
[i
].first
= queue
->msg_list
[i
].last
= NULL
;
128 thread
->queue
= queue
;
129 if (!thread
->process
->queue
)
130 thread
->process
->queue
= (struct msg_queue
*)grab_object( queue
);
135 /* check the queue status */
136 inline static int is_signaled( struct msg_queue
*queue
)
138 return ((queue
->wake_bits
& queue
->wake_mask
) || (queue
->changed_bits
& queue
->changed_mask
));
141 /* set/clear some queue bits */
142 inline static void change_queue_bits( struct msg_queue
*queue
, unsigned int set
, unsigned int clear
)
144 queue
->wake_bits
= (queue
->wake_bits
| set
) & ~clear
;
145 queue
->changed_bits
= (queue
->changed_bits
| set
) & ~clear
;
146 if (is_signaled( queue
)) wake_up( &queue
->obj
, 0 );
149 /* get the QS_* bit corresponding to a given hardware message */
150 inline static int get_hardware_msg_bit( struct message
*msg
)
152 if (msg
->msg
== WM_MOUSEMOVE
|| msg
->msg
== WM_NCMOUSEMOVE
) return QS_MOUSEMOVE
;
153 if (msg
->msg
>= WM_KEYFIRST
&& msg
->msg
<= WM_KEYLAST
) return QS_KEY
;
154 return QS_MOUSEBUTTON
;
157 /* get the current thread queue, creating it if needed */
158 inline struct msg_queue
*get_current_queue(void)
160 struct msg_queue
*queue
= current
->queue
;
161 if (!queue
) queue
= create_msg_queue( current
);
165 /* append a message to the end of a list */
166 inline static void append_message( struct message_list
*list
, struct message
*msg
)
169 if ((msg
->prev
= list
->last
)) msg
->prev
->next
= msg
;
170 else list
->first
= msg
;
174 /* unlink a message from a list it */
175 inline static void unlink_message( struct message_list
*list
, struct message
*msg
)
177 if (msg
->next
) msg
->next
->prev
= msg
->prev
;
178 else list
->last
= msg
->prev
;
179 if (msg
->prev
) msg
->prev
->next
= msg
->next
;
180 else list
->first
= msg
->next
;
183 /* free a message when deleting a queue or window */
184 static void free_message( struct message
*msg
)
186 struct message_result
*result
= msg
->result
;
192 result
->error
= STATUS_ACCESS_DENIED
; /* FIXME */
194 result
->receiver
= NULL
;
195 /* wake sender queue if waiting on this result */
196 if (result
->sender
->send_result
== result
)
197 change_queue_bits( result
->sender
, QS_SMRESULT
, 0 );
204 /* remove (and free) a message from a message list */
205 static void remove_queue_message( struct msg_queue
*queue
, struct message
*msg
,
206 enum message_kind kind
)
209 struct message
*other
;
211 unlink_message( &queue
->msg_list
[kind
], msg
);
215 if (!queue
->msg_list
[kind
].first
) change_queue_bits( queue
, 0, QS_SENDMESSAGE
);
218 if (!queue
->msg_list
[kind
].first
) change_queue_bits( queue
, 0, QS_POSTMESSAGE
);
220 case COOKED_HW_MESSAGE
:
222 clr_bit
= get_hardware_msg_bit( msg
);
223 for (other
= queue
->msg_list
[kind
].first
; other
; other
= other
->next
)
224 if (get_hardware_msg_bit( other
) == clr_bit
) break;
225 if (!other
) change_queue_bits( queue
, 0, clr_bit
);
231 /* send a message from the sender queue to the receiver queue */
232 static int send_message( struct msg_queue
*send_queue
, struct msg_queue
*recv_queue
,
233 struct message
*msg
)
235 struct message_result
*result
= mem_alloc( sizeof(*result
) );
236 if (!result
) return 0;
238 /* put the result on the sender result stack */
239 result
->sender
= send_queue
;
240 result
->receiver
= recv_queue
;
242 result
->send_next
= send_queue
->send_result
;
243 send_queue
->send_result
= result
;
245 /* and put the message on the receiver queue */
246 msg
->result
= result
;
247 append_message( &recv_queue
->msg_list
[SEND_MESSAGE
], msg
);
248 change_queue_bits( recv_queue
, QS_SENDMESSAGE
, 0 );
252 /* receive a message, removing it from the sent queue */
253 static void receive_message( struct msg_queue
*queue
, struct message
*msg
)
255 struct message_result
*result
= msg
->result
;
257 unlink_message( &queue
->msg_list
[SEND_MESSAGE
], msg
);
258 /* put the result on the receiver result stack */
259 result
->recv_next
= queue
->recv_result
;
260 queue
->recv_result
= result
;
262 if (!queue
->msg_list
[SEND_MESSAGE
].first
) change_queue_bits( queue
, 0, QS_SENDMESSAGE
);
265 /* set the result of the current received message */
266 static void reply_message( struct msg_queue
*queue
, unsigned int result
,
267 unsigned int error
, int remove
)
269 struct message_result
*res
= queue
->recv_result
;
273 queue
->recv_result
= res
->recv_next
;
274 res
->receiver
= NULL
;
275 if (!res
->sender
) /* no one waiting for it */
283 res
->result
= result
;
286 /* wake sender queue if waiting on this result */
287 if (res
->sender
&& res
->sender
->send_result
== res
)
288 change_queue_bits( res
->sender
, QS_SMRESULT
, 0 );
292 /* retrieve the reply of the current message being sent */
293 static unsigned int get_message_reply( struct msg_queue
*queue
, int cancel
)
295 struct message_result
*res
= queue
->send_result
;
296 unsigned int ret
= 0;
298 set_error( STATUS_PENDING
);
300 if (res
&& (res
->replied
|| cancel
))
305 set_error( res
->error
);
307 queue
->send_result
= res
->send_next
;
309 if (!res
->receiver
) free( res
);
310 if (!queue
->send_result
|| !queue
->send_result
->replied
)
311 change_queue_bits( queue
, 0, QS_SMRESULT
);
316 /* empty a message list and free all the messages */
317 static void empty_msg_list( struct message_list
*list
)
319 struct message
*msg
= list
->first
;
322 struct message
*next
= msg
->next
;
328 /* cleanup all pending results when deleting a queue */
329 static void cleanup_results( struct msg_queue
*queue
)
331 struct message_result
*result
, *next
;
333 result
= queue
->send_result
;
336 next
= result
->send_next
;
337 result
->sender
= NULL
;
338 if (!result
->receiver
) free( result
);
342 while (queue
->recv_result
) reply_message( queue
, 0, STATUS_ACCESS_DENIED
/*FIXME*/, 1 );
345 static int msg_queue_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
347 struct msg_queue
*queue
= (struct msg_queue
*)obj
;
348 struct process
*process
= entry
->thread
->process
;
350 /* a thread can only wait on its own queue */
351 if (entry
->thread
->queue
!= queue
)
353 set_error( STATUS_ACCESS_DENIED
);
356 /* if waiting on the main process queue, set the idle event */
357 if (process
->queue
== queue
)
359 if (process
->idle_event
) set_event( process
->idle_event
);
361 add_queue( obj
, entry
);
365 static void msg_queue_remove_queue(struct object
*obj
, struct wait_queue_entry
*entry
)
367 struct msg_queue
*queue
= (struct msg_queue
*)obj
;
368 struct process
*process
= entry
->thread
->process
;
370 remove_queue( obj
, entry
);
372 assert( entry
->thread
->queue
== queue
);
374 /* if waiting on the main process queue, reset the idle event */
375 if (process
->queue
== queue
)
377 if (process
->idle_event
) reset_event( process
->idle_event
);
381 static void msg_queue_dump( struct object
*obj
, int verbose
)
383 struct msg_queue
*queue
= (struct msg_queue
*)obj
;
384 fprintf( stderr
, "Msg queue bits=%x mask=%x\n",
385 queue
->wake_bits
, queue
->wake_mask
);
388 static int msg_queue_signaled( struct object
*obj
, struct thread
*thread
)
390 struct msg_queue
*queue
= (struct msg_queue
*)obj
;
391 return is_signaled( queue
);
394 static int msg_queue_satisfied( struct object
*obj
, struct thread
*thread
)
396 struct msg_queue
*queue
= (struct msg_queue
*)obj
;
397 queue
->wake_mask
= 0;
398 queue
->changed_mask
= 0;
399 return 0; /* Not abandoned */
402 static void msg_queue_destroy( struct object
*obj
)
404 struct msg_queue
*queue
= (struct msg_queue
*)obj
;
405 struct timer
*timer
= queue
->first_timer
;
408 cleanup_results( queue
);
409 for (i
= 0; i
< NB_MSG_KINDS
; i
++) empty_msg_list( &queue
->msg_list
[i
] );
413 struct timer
*next
= timer
->next
;
417 if (queue
->timeout
) remove_timeout_user( queue
->timeout
);
420 /* set the next timer to expire */
421 static void set_next_timer( struct msg_queue
*queue
, struct timer
*timer
)
425 remove_timeout_user( queue
->timeout
);
426 queue
->timeout
= NULL
;
428 if ((queue
->next_timer
= timer
))
429 queue
->timeout
= add_timeout_user( &timer
->when
, timer_callback
, queue
);
431 /* set/clear QS_TIMER bit */
432 if (queue
->next_timer
== queue
->first_timer
)
433 change_queue_bits( queue
, 0, QS_TIMER
);
435 change_queue_bits( queue
, QS_TIMER
, 0 );
438 /* callback for the next timer expiration */
439 static void timer_callback( void *private )
441 struct msg_queue
*queue
= private;
443 queue
->timeout
= NULL
;
444 /* move on to the next timer */
445 set_next_timer( queue
, queue
->next_timer
->next
);
448 /* link a timer at its rightful place in the queue list */
449 static void link_timer( struct msg_queue
*queue
, struct timer
*timer
)
451 struct timer
*pos
= queue
->next_timer
;
453 while (pos
&& time_before( &pos
->when
, &timer
->when
)) pos
= pos
->next
;
455 if (pos
) /* insert before pos */
457 if ((timer
->prev
= pos
->prev
)) timer
->prev
->next
= timer
;
458 else queue
->first_timer
= timer
;
462 else /* insert at end */
465 timer
->prev
= queue
->last_timer
;
466 if (queue
->last_timer
) queue
->last_timer
->next
= timer
;
467 else queue
->first_timer
= timer
;
468 queue
->last_timer
= timer
;
470 /* check if we replaced the next timer */
471 if (pos
== queue
->next_timer
) set_next_timer( queue
, timer
);
474 /* remove a timer from the queue timer list */
475 static void unlink_timer( struct msg_queue
*queue
, struct timer
*timer
)
477 if (timer
->next
) timer
->next
->prev
= timer
->prev
;
478 else queue
->last_timer
= timer
->prev
;
479 if (timer
->prev
) timer
->prev
->next
= timer
->next
;
480 else queue
->first_timer
= timer
->next
;
481 /* check if we removed the next timer */
482 if (queue
->next_timer
== timer
) set_next_timer( queue
, timer
->next
);
483 else if (queue
->next_timer
== queue
->first_timer
) change_queue_bits( queue
, 0, QS_TIMER
);
486 /* restart an expired timer */
487 static void restart_timer( struct msg_queue
*queue
, struct timer
*timer
)
490 unlink_timer( queue
, timer
);
491 gettimeofday( &now
, 0 );
492 while (!time_before( &now
, &timer
->when
)) add_timeout( &timer
->when
, timer
->rate
);
493 link_timer( queue
, timer
);
496 /* find an expired timer matching the filtering parameters */
497 static struct timer
*find_expired_timer( struct msg_queue
*queue
, handle_t win
,
498 unsigned int get_first
, unsigned int get_last
,
502 for (timer
= queue
->first_timer
; (timer
&& timer
!= queue
->next_timer
); timer
= timer
->next
)
504 if (win
&& timer
->win
!= win
) continue;
505 if (timer
->msg
>= get_first
&& timer
->msg
<= get_last
)
507 if (remove
) restart_timer( queue
, timer
);
515 static int kill_timer( struct msg_queue
*queue
, handle_t win
, unsigned int msg
, unsigned int id
)
519 for (timer
= queue
->first_timer
; timer
; timer
= timer
->next
)
521 if (timer
->win
!= win
|| timer
->msg
!= msg
|| timer
->id
!= id
) continue;
522 unlink_timer( queue
, timer
);
530 static struct timer
*set_timer( struct msg_queue
*queue
, unsigned int rate
)
532 struct timer
*timer
= mem_alloc( sizeof(*timer
) );
536 gettimeofday( &timer
->when
, 0 );
537 add_timeout( &timer
->when
, rate
);
538 link_timer( queue
, timer
);
543 /* remove all messages and timers belonging to a certain window */
544 static void cleanup_window( struct msg_queue
*queue
, handle_t win
)
551 timer
= queue
->first_timer
;
554 struct timer
*next
= timer
->next
;
555 if (timer
->win
== win
)
557 unlink_timer( queue
, timer
);
563 /* remove messages */
564 for (i
= 0; i
< NB_MSG_KINDS
; i
++)
566 msg
= queue
->msg_list
[i
].first
;
569 struct message
*next
= msg
->next
;
570 if (msg
->win
== win
) remove_queue_message( queue
, msg
, i
);
576 /* get the message queue of the current thread */
577 DECL_HANDLER(get_msg_queue
)
579 struct msg_queue
*queue
= get_current_queue();
582 if (queue
) req
->handle
= alloc_handle( current
->process
, queue
, SYNCHRONIZE
, 0 );
586 /* increment the message queue paint count */
587 DECL_HANDLER(inc_queue_paint_count
)
589 struct msg_queue
*queue
;
590 struct thread
*thread
= get_thread_from_id( req
->id
);
594 if ((queue
= thread
->queue
))
596 if ((queue
->paint_count
+= req
->incr
) < 0) queue
->paint_count
= 0;
598 if (queue
->paint_count
)
599 change_queue_bits( queue
, QS_PAINT
, 0 );
601 change_queue_bits( queue
, 0, QS_PAINT
);
603 else set_error( STATUS_INVALID_PARAMETER
);
605 release_object( thread
);
610 /* set the current message queue wakeup mask */
611 DECL_HANDLER(set_queue_mask
)
613 struct msg_queue
*queue
= get_current_queue();
617 queue
->wake_mask
= req
->wake_mask
;
618 queue
->changed_mask
= req
->changed_mask
;
619 req
->wake_bits
= queue
->wake_bits
;
620 req
->changed_bits
= queue
->changed_bits
;
621 if (is_signaled( queue
))
623 /* if skip wait is set, do what would have been done in the subsequent wait */
624 if (req
->skip_wait
) msg_queue_satisfied( &queue
->obj
, current
);
625 else wake_up( &queue
->obj
, 0 );
631 /* get the current message queue status */
632 DECL_HANDLER(get_queue_status
)
634 struct msg_queue
*queue
= current
->queue
;
637 req
->wake_bits
= queue
->wake_bits
;
638 req
->changed_bits
= queue
->changed_bits
;
639 if (req
->clear
) queue
->changed_bits
= 0;
641 else req
->wake_bits
= req
->changed_bits
= 0;
645 /* send a message to a thread queue */
646 DECL_HANDLER(send_message
)
649 struct msg_queue
*send_queue
= get_current_queue();
650 struct msg_queue
*recv_queue
;
651 struct thread
*thread
= get_thread_from_id( req
->id
);
655 if (!(recv_queue
= thread
->queue
))
657 set_error( STATUS_INVALID_PARAMETER
);
658 release_object( thread
);
662 if ((msg
= mem_alloc( sizeof(*msg
) )))
664 msg
->type
= req
->type
;
667 msg
->wparam
= req
->wparam
;
668 msg
->lparam
= req
->lparam
;
671 msg
->time
= req
->time
;
672 msg
->info
= req
->info
;
677 send_message( send_queue
, recv_queue
, msg
);
680 append_message( &recv_queue
->msg_list
[POST_MESSAGE
], msg
);
681 change_queue_bits( recv_queue
, QS_POSTMESSAGE
, 0 );
683 case COOKED_HW_MESSAGE
:
685 append_message( &recv_queue
->msg_list
[req
->kind
], msg
);
686 change_queue_bits( recv_queue
, get_hardware_msg_bit(msg
), 0 );
690 set_error( STATUS_INVALID_PARAMETER
);
694 release_object( thread
);
697 /* store a message contents into the request buffer; helper for get_message */
698 inline static void put_req_message( struct get_message_request
*req
, const struct message
*msg
)
700 req
->type
= msg
->type
;
703 req
->wparam
= msg
->wparam
;
704 req
->lparam
= msg
->lparam
;
707 req
->time
= msg
->time
;
708 req
->info
= msg
->info
;
711 inline static struct message
*find_matching_message( const struct message_list
*list
, handle_t win
,
712 unsigned int first
, unsigned int last
)
716 for (msg
= list
->first
; msg
; msg
= msg
->next
)
718 /* check against the filters */
719 if (win
&& msg
->win
&& msg
->win
!= win
) continue;
720 if (msg
->msg
< first
) continue;
721 if (msg
->msg
> last
) continue;
722 break; /* found one */
728 /* get a message from the current queue */
729 DECL_HANDLER(get_message
)
733 struct msg_queue
*queue
= get_current_queue();
737 /* first check for sent messages */
738 if ((msg
= queue
->msg_list
[SEND_MESSAGE
].first
))
740 req
->kind
= SEND_MESSAGE
;
741 put_req_message( req
, msg
);
742 receive_message( queue
, msg
);
745 if (req
->flags
& GET_MSG_SENT_ONLY
) goto done
; /* nothing else to check */
747 /* then check for posted messages */
748 if ((msg
= find_matching_message( &queue
->msg_list
[POST_MESSAGE
], req
->get_win
,
749 req
->get_first
, req
->get_last
)))
751 req
->kind
= POST_MESSAGE
;
752 put_req_message( req
, msg
);
753 if (req
->flags
& GET_MSG_REMOVE
) remove_queue_message( queue
, msg
, POST_MESSAGE
);
757 /* then check for cooked hardware messages */
758 if ((msg
= find_matching_message( &queue
->msg_list
[COOKED_HW_MESSAGE
], req
->get_win
,
759 req
->get_first
, req
->get_last
)))
761 req
->kind
= COOKED_HW_MESSAGE
;
762 put_req_message( req
, msg
);
763 if (req
->flags
& GET_MSG_REMOVE
) remove_queue_message( queue
, msg
, COOKED_HW_MESSAGE
);
767 /* then check for any raw hardware message */
768 if ((msg
= queue
->msg_list
[RAW_HW_MESSAGE
].first
))
770 req
->kind
= RAW_HW_MESSAGE
;
771 put_req_message( req
, msg
);
772 /* raw messages always get removed */
773 remove_queue_message( queue
, msg
, RAW_HW_MESSAGE
);
777 /* now check for WM_PAINT */
778 if ((queue
->wake_bits
& QS_PAINT
) &&
779 (WM_PAINT
>= req
->get_first
) && (WM_PAINT
<= req
->get_last
))
781 req
->kind
= POST_MESSAGE
;
794 /* now check for timer */
795 if ((timer
= find_expired_timer( queue
, req
->get_win
, req
->get_first
,
796 req
->get_last
, (req
->flags
& GET_MSG_REMOVE
) )))
798 req
->kind
= POST_MESSAGE
;
800 req
->win
= timer
->win
;
801 req
->msg
= timer
->msg
;
802 req
->wparam
= timer
->id
;
803 req
->lparam
= timer
->lparam
;
812 set_error( STATUS_PENDING
); /* FIXME */
816 /* reply to a sent message */
817 DECL_HANDLER(reply_message
)
819 if (current
->queue
&& current
->queue
->recv_result
)
820 reply_message( current
->queue
, req
->result
, 0, req
->remove
);
822 set_error( STATUS_ACCESS_DENIED
);
826 /* retrieve the reply for the last message sent */
827 DECL_HANDLER(get_message_reply
)
829 if (current
->queue
) req
->result
= get_message_reply( current
->queue
, req
->cancel
);
830 else set_error( STATUS_ACCESS_DENIED
);
834 /* check if we are processing a sent message */
835 DECL_HANDLER(in_send_message
)
841 struct message_result
*result
= current
->queue
->recv_result
;
844 flags
|= ISMEX_SEND
; /* FIXME */
845 if (result
->replied
|| !result
->sender
) flags
|= ISMEX_REPLIED
;
852 /* cleanup a queue when a window is deleted */
853 DECL_HANDLER(cleanup_window_queue
)
855 if (current
->queue
) cleanup_window( current
->queue
, req
->win
);
859 /* set a window timer */
860 DECL_HANDLER(set_win_timer
)
863 struct msg_queue
*queue
= get_current_queue();
867 /* remove it if it existed already */
868 if (req
->win
) kill_timer( queue
, req
->win
, req
->msg
, req
->id
);
870 if ((timer
= set_timer( queue
, req
->rate
)))
872 timer
->win
= req
->win
;
873 timer
->msg
= req
->msg
;
875 timer
->lparam
= req
->lparam
;
879 /* kill a window timer */
880 DECL_HANDLER(kill_win_timer
)
882 struct msg_queue
*queue
= current
->queue
;
884 if (!queue
|| !kill_timer( queue
, req
->win
, req
->msg
, req
->id
))
885 set_error( STATUS_INVALID_PARAMETER
);