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 struct message_list msg_list[NB_MSG_KINDS]; /* lists of messages */
73 struct message_result *send_result; /* stack of sent messages waiting for result */
74 struct message_result *recv_result; /* stack of received messages waiting for result */
75 struct timer *first_timer; /* head of timer list */
76 struct timer *last_timer; /* tail of timer list */
77 struct timer *next_timer; /* next timer to expire */
78 struct timeout_user *timeout; /* timeout for next timer to expire */
81 static void msg_queue_dump( struct object *obj, int verbose );
82 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry );
83 static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry );
84 static int msg_queue_signaled( struct object *obj, struct thread *thread );
85 static int msg_queue_satisfied( struct object *obj, struct thread *thread );
86 static void msg_queue_destroy( struct object *obj );
87 static void timer_callback( void *private );
89 static const struct object_ops msg_queue_ops =
91 sizeof(struct msg_queue), /* size */
92 msg_queue_dump, /* dump */
93 msg_queue_add_queue, /* add_queue */
94 msg_queue_remove_queue, /* remove_queue */
95 msg_queue_signaled, /* signaled */
96 msg_queue_satisfied, /* satisfied */
97 NULL, /* get_poll_events */
98 NULL, /* poll_event */
99 no_get_fd, /* get_fd */
100 no_flush, /* flush */
101 no_get_file_info, /* get_file_info */
102 msg_queue_destroy /* destroy */
106 static struct msg_queue *create_msg_queue( struct thread *thread )
108 struct msg_queue *queue;
111 if ((queue = alloc_object( &msg_queue_ops, -1 )))
113 queue->wake_bits = 0;
114 queue->wake_mask = 0;
115 queue->changed_bits = 0;
116 queue->changed_mask = 0;
117 queue->send_result = NULL;
118 queue->recv_result = NULL;
119 queue->first_timer = NULL;
120 queue->last_timer = NULL;
121 queue->next_timer = NULL;
122 queue->timeout = NULL;
123 for (i = 0; i < NB_MSG_KINDS; i++)
124 queue->msg_list[i].first = queue->msg_list[i].last = NULL;
126 thread->queue = queue;
127 if (!thread->process->queue)
128 thread->process->queue = (struct msg_queue *)grab_object( queue );
133 /* check the queue status */
134 inline static int is_signaled( struct msg_queue *queue )
136 return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask));
139 /* set/clear some queue bits */
140 inline static void change_queue_bits( struct msg_queue *queue, unsigned int set, unsigned int clear )
142 queue->wake_bits = (queue->wake_bits | set) & ~clear;
143 queue->changed_bits = (queue->changed_bits | set) & ~clear;
144 if (is_signaled( queue )) wake_up( &queue->obj, 0 );
147 /* get the QS_* bit corresponding to a given hardware message */
148 inline static int get_hardware_msg_bit( struct message *msg )
150 if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) return QS_MOUSEMOVE;
151 if (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST) return QS_KEY;
152 return QS_MOUSEBUTTON;
155 /* get the current thread queue, creating it if needed */
156 inline struct msg_queue *get_current_queue(void)
158 struct msg_queue *queue = current->queue;
159 if (!queue) queue = create_msg_queue( current );
163 /* append a message to the end of a list */
164 inline static void append_message( struct message_list *list, struct message *msg )
167 if ((msg->prev = list->last)) msg->prev->next = msg;
168 else list->first = msg;
172 /* unlink a message from a list it */
173 inline static void unlink_message( struct message_list *list, struct message *msg )
175 if (msg->next) msg->next->prev = msg->prev;
176 else list->last = msg->prev;
177 if (msg->prev) msg->prev->next = msg->next;
178 else list->first = msg->next;
181 /* free a message when deleting a queue or window */
182 static void free_message( struct message *msg )
184 struct message_result *result = msg->result;
190 result->error = STATUS_ACCESS_DENIED; /* FIXME */
192 result->receiver = NULL;
193 /* wake sender queue if waiting on this result */
194 if (result->sender->send_result == result)
195 change_queue_bits( result->sender, QS_SMRESULT, 0 );
202 /* remove (and free) a message from a message list */
203 static void remove_queue_message( struct msg_queue *queue, struct message *msg,
204 enum message_kind kind )
207 struct message *other;
209 unlink_message( &queue->msg_list[kind], msg );
213 if (!queue->msg_list[kind].first) change_queue_bits( queue, 0, QS_SENDMESSAGE );
216 if (!queue->msg_list[kind].first) change_queue_bits( queue, 0, QS_POSTMESSAGE );
218 case COOKED_HW_MESSAGE:
220 clr_bit = get_hardware_msg_bit( msg );
221 for (other = queue->msg_list[kind].first; other; other = other->next)
222 if (get_hardware_msg_bit( other ) == clr_bit) break;
223 if (!other) change_queue_bits( queue, 0, clr_bit );
229 /* send a message from the sender queue to the receiver queue */
230 static int send_message( struct msg_queue *send_queue, struct msg_queue *recv_queue,
231 struct message *msg )
233 struct message_result *result = mem_alloc( sizeof(*result) );
234 if (!result) return 0;
236 /* put the result on the sender result stack */
237 result->sender = send_queue;
238 result->receiver = recv_queue;
240 result->send_next = send_queue->send_result;
241 send_queue->send_result = result;
243 /* and put the message on the receiver queue */
244 msg->result = result;
245 append_message( &recv_queue->msg_list[SEND_MESSAGE], msg );
246 change_queue_bits( recv_queue, QS_SENDMESSAGE, 0 );
250 /* receive a message, removing it from the sent queue */
251 static void receive_message( struct msg_queue *queue, struct message *msg )
253 struct message_result *result = msg->result;
255 unlink_message( &queue->msg_list[SEND_MESSAGE], msg );
256 /* put the result on the receiver result stack */
257 result->recv_next = queue->recv_result;
258 queue->recv_result = result;
260 if (!queue->msg_list[SEND_MESSAGE].first) change_queue_bits( queue, 0, QS_SENDMESSAGE );
263 /* set the result of the current received message */
264 static void reply_message( struct msg_queue *queue, unsigned int result,
265 unsigned int error, int remove )
267 struct message_result *res = queue->recv_result;
271 queue->recv_result = res->recv_next;
272 res->receiver = NULL;
273 if (!res->sender) /* no one waiting for it */
281 res->result = result;
284 /* wake sender queue if waiting on this result */
285 if (res->sender && res->sender->send_result == res)
286 change_queue_bits( res->sender, QS_SMRESULT, 0 );
290 /* retrieve the reply of the current message being sent */
291 static unsigned int get_message_reply( struct msg_queue *queue, int cancel )
293 struct message_result *res = queue->send_result;
294 unsigned int ret = 0;
296 set_error( STATUS_PENDING );
298 if (res && (res->replied || cancel))
303 set_error( res->error );
305 queue->send_result = res->send_next;
307 if (!res->receiver) free( res );
308 if (!queue->send_result || !queue->send_result->replied)
309 change_queue_bits( queue, 0, QS_SMRESULT );
314 /* empty a message list and free all the messages */
315 static void empty_msg_list( struct message_list *list )
317 struct message *msg = list->first;
320 struct message *next = msg->next;
326 /* cleanup all pending results when deleting a queue */
327 static void cleanup_results( struct msg_queue *queue )
329 struct message_result *result, *next;
331 result = queue->send_result;
334 next = result->send_next;
335 result->sender = NULL;
336 if (!result->receiver) free( result );
340 while (queue->recv_result) reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1 );
343 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
345 struct msg_queue *queue = (struct msg_queue *)obj;
346 struct process *process = entry->thread->process;
348 /* a thread can only wait on its own queue */
349 if (entry->thread->queue != queue)
351 set_error( STATUS_ACCESS_DENIED );
354 /* if waiting on the main process queue, set the idle event */
355 if (process->queue == queue)
357 if (process->idle_event) set_event( process->idle_event );
359 add_queue( obj, entry );
363 static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry *entry )
365 struct msg_queue *queue = (struct msg_queue *)obj;
366 struct process *process = entry->thread->process;
368 remove_queue( obj, entry );
370 assert( entry->thread->queue == queue );
372 /* if waiting on the main process queue, reset the idle event */
373 if (process->queue == queue)
375 if (process->idle_event) reset_event( process->idle_event );
379 static void msg_queue_dump( struct object *obj, int verbose )
381 struct msg_queue *queue = (struct msg_queue *)obj;
382 fprintf( stderr, "Msg queue bits=%x mask=%x\n",
383 queue->wake_bits, queue->wake_mask );
386 static int msg_queue_signaled( struct object *obj, struct thread *thread )
388 struct msg_queue *queue = (struct msg_queue *)obj;
389 return is_signaled( queue );
392 static int msg_queue_satisfied( struct object *obj, struct thread *thread )
394 struct msg_queue *queue = (struct msg_queue *)obj;
395 queue->wake_mask = 0;
396 queue->changed_mask = 0;
397 return 0; /* Not abandoned */
400 static void msg_queue_destroy( struct object *obj )
402 struct msg_queue *queue = (struct msg_queue *)obj;
403 struct timer *timer = queue->first_timer;
406 cleanup_results( queue );
407 for (i = 0; i < NB_MSG_KINDS; i++) empty_msg_list( &queue->msg_list[i] );
411 struct timer *next = timer->next;
415 if (queue->timeout) remove_timeout_user( queue->timeout );
418 /* set the next timer to expire */
419 static void set_next_timer( struct msg_queue *queue, struct timer *timer )
423 remove_timeout_user( queue->timeout );
424 queue->timeout = NULL;
426 if ((queue->next_timer = timer))
427 queue->timeout = add_timeout_user( &timer->when, timer_callback, queue );
429 /* set/clear QS_TIMER bit */
430 if (queue->next_timer == queue->first_timer)
431 change_queue_bits( queue, 0, QS_TIMER );
433 change_queue_bits( queue, QS_TIMER, 0 );
436 /* callback for the next timer expiration */
437 static void timer_callback( void *private )
439 struct msg_queue *queue = private;
441 queue->timeout = NULL;
442 /* move on to the next timer */
443 set_next_timer( queue, queue->next_timer->next );
446 /* link a timer at its rightful place in the queue list */
447 static void link_timer( struct msg_queue *queue, struct timer *timer )
449 struct timer *pos = queue->next_timer;
451 while (pos && time_before( &pos->when, &timer->when )) pos = pos->next;
453 if (pos) /* insert before pos */
455 if ((timer->prev = pos->prev)) timer->prev->next = timer;
456 else queue->first_timer = timer;
460 else /* insert at end */
463 timer->prev = queue->last_timer;
464 if (queue->last_timer) queue->last_timer->next = timer;
465 else queue->first_timer = timer;
466 queue->last_timer = timer;
468 /* check if we replaced the next timer */
469 if (pos == queue->next_timer) set_next_timer( queue, timer );
472 /* remove a timer from the queue timer list */
473 static void unlink_timer( struct msg_queue *queue, struct timer *timer )
475 if (timer->next) timer->next->prev = timer->prev;
476 else queue->last_timer = timer->prev;
477 if (timer->prev) timer->prev->next = timer->next;
478 else queue->first_timer = timer->next;
479 /* check if we removed the next timer */
480 if (queue->next_timer == timer) set_next_timer( queue, timer->next );
481 else if (queue->next_timer == queue->first_timer) change_queue_bits( queue, 0, QS_TIMER );
484 /* restart an expired timer */
485 static void restart_timer( struct msg_queue *queue, struct timer *timer )
488 unlink_timer( queue, timer );
489 gettimeofday( &now, 0 );
490 while (!time_before( &now, &timer->when )) add_timeout( &timer->when, timer->rate );
491 link_timer( queue, timer );
494 /* find an expired timer matching the filtering parameters */
495 static struct timer *find_expired_timer( struct msg_queue *queue, handle_t win,
496 unsigned int get_first, unsigned int get_last,
500 for (timer = queue->first_timer; (timer && timer != queue->next_timer); timer = timer->next)
502 if (win && timer->win != win) continue;
503 if (timer->msg >= get_first && timer->msg <= get_last)
505 if (remove) restart_timer( queue, timer );
513 static int kill_timer( struct msg_queue *queue, handle_t win, unsigned int msg, unsigned int id )
517 for (timer = queue->first_timer; timer; timer = timer->next)
519 if (timer->win != win || timer->msg != msg || timer->id != id) continue;
520 unlink_timer( queue, timer );
528 static struct timer *set_timer( struct msg_queue *queue, unsigned int rate )
530 struct timer *timer = mem_alloc( sizeof(*timer) );
534 gettimeofday( &timer->when, 0 );
535 add_timeout( &timer->when, rate );
536 link_timer( queue, timer );
541 /* remove all messages and timers belonging to a certain window */
542 static void cleanup_window( struct msg_queue *queue, handle_t win )
549 timer = queue->first_timer;
552 struct timer *next = timer->next;
553 if (timer->win == win)
555 unlink_timer( queue, timer );
561 /* remove messages */
562 for (i = 0; i < NB_MSG_KINDS; i++)
564 msg = queue->msg_list[i].first;
567 struct message *next = msg->next;
568 if (msg->win == win) remove_queue_message( queue, msg, i );
574 /* get the message queue of the current thread */
575 DECL_HANDLER(get_msg_queue)
577 struct msg_queue *queue = get_current_queue();
580 if (queue) req->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 );
584 /* set the message queue wake bits */
585 DECL_HANDLER(set_queue_bits)
587 struct msg_queue *queue = (struct msg_queue *)get_handle_obj( current->process, req->handle,
591 req->changed_mask = queue->changed_mask;
592 if (!req->mask_cond || (queue->changed_mask & req->mask_cond))
593 change_queue_bits( queue, req->set, req->clear );
594 release_object( queue );
599 /* set the current message queue wakeup mask */
600 DECL_HANDLER(set_queue_mask)
602 struct msg_queue *queue = get_current_queue();
606 queue->wake_mask = req->wake_mask;
607 queue->changed_mask = req->changed_mask;
608 req->wake_bits = queue->wake_bits;
609 req->changed_bits = queue->changed_bits;
610 if (is_signaled( queue ))
612 /* if skip wait is set, do what would have been done in the subsequent wait */
613 if (req->skip_wait) msg_queue_satisfied( &queue->obj, current );
614 else wake_up( &queue->obj, 0 );
620 /* get the current message queue status */
621 DECL_HANDLER(get_queue_status)
623 struct msg_queue *queue = current->queue;
626 req->wake_bits = queue->wake_bits;
627 req->changed_bits = queue->changed_bits;
628 if (req->clear) queue->changed_bits = 0;
630 else req->wake_bits = req->changed_bits = 0;
634 /* send a message to a thread queue */
635 DECL_HANDLER(send_message)
638 struct msg_queue *send_queue = get_current_queue();
639 struct msg_queue *recv_queue;
640 struct thread *thread = get_thread_from_id( req->id );
644 if (!(recv_queue = thread->queue))
646 set_error( STATUS_INVALID_PARAMETER );
647 release_object( thread );
651 if ((msg = mem_alloc( sizeof(*msg) )))
653 msg->type = req->type;
656 msg->wparam = req->wparam;
657 msg->lparam = req->lparam;
660 msg->time = req->time;
661 msg->info = req->info;
666 send_message( send_queue, recv_queue, msg );
669 append_message( &recv_queue->msg_list[POST_MESSAGE], msg );
670 change_queue_bits( recv_queue, QS_POSTMESSAGE, 0 );
672 case COOKED_HW_MESSAGE:
674 append_message( &recv_queue->msg_list[req->kind], msg );
675 change_queue_bits( recv_queue, get_hardware_msg_bit(msg), 0 );
679 set_error( STATUS_INVALID_PARAMETER );
683 release_object( thread );
686 /* store a message contents into the request buffer; helper for get_message */
687 inline static void put_req_message( struct get_message_request *req, const struct message *msg )
689 req->type = msg->type;
692 req->wparam = msg->wparam;
693 req->lparam = msg->lparam;
696 req->time = msg->time;
697 req->info = msg->info;
700 inline static struct message *find_matching_message( const struct message_list *list, handle_t win,
701 unsigned int first, unsigned int last )
705 for (msg = list->first; msg; msg = msg->next)
707 /* check against the filters */
708 if (win && msg->win && msg->win != win) continue;
709 if (msg->msg < first) continue;
710 if (msg->msg > last) continue;
711 break; /* found one */
717 /* get a message from the current queue */
718 DECL_HANDLER(get_message)
722 struct msg_queue *queue = get_current_queue();
726 /* first check for sent messages */
727 if ((msg = queue->msg_list[SEND_MESSAGE].first))
729 req->kind = SEND_MESSAGE;
730 put_req_message( req, msg );
731 receive_message( queue, msg );
734 if (req->flags & GET_MSG_SENT_ONLY) goto done; /* nothing else to check */
736 /* then check for posted messages */
737 if ((msg = find_matching_message( &queue->msg_list[POST_MESSAGE], req->get_win,
738 req->get_first, req->get_last )))
740 req->kind = POST_MESSAGE;
741 put_req_message( req, msg );
742 if (req->flags & GET_MSG_REMOVE) remove_queue_message( queue, msg, POST_MESSAGE );
746 /* then check for cooked hardware messages */
747 if ((msg = find_matching_message( &queue->msg_list[COOKED_HW_MESSAGE], req->get_win,
748 req->get_first, req->get_last )))
750 req->kind = COOKED_HW_MESSAGE;
751 put_req_message( req, msg );
752 if (req->flags & GET_MSG_REMOVE) remove_queue_message( queue, msg, COOKED_HW_MESSAGE );
756 /* then check for any raw hardware message */
757 if ((msg = queue->msg_list[RAW_HW_MESSAGE].first))
759 req->kind = RAW_HW_MESSAGE;
760 put_req_message( req, msg );
761 /* raw messages always get removed */
762 remove_queue_message( queue, msg, RAW_HW_MESSAGE );
766 /* now check for WM_PAINT */
767 if ((queue->wake_bits & QS_PAINT) &&
768 (WM_PAINT >= req->get_first) && (WM_PAINT <= req->get_last))
770 req->kind = POST_MESSAGE;
783 /* now check for timer */
784 if ((timer = find_expired_timer( queue, req->get_win, req->get_first,
785 req->get_last, (req->flags & GET_MSG_REMOVE) )))
787 req->kind = POST_MESSAGE;
789 req->win = timer->win;
790 req->msg = timer->msg;
791 req->wparam = timer->id;
792 req->lparam = timer->lparam;
801 set_error( STATUS_PENDING ); /* FIXME */
805 /* reply to a sent message */
806 DECL_HANDLER(reply_message)
808 if (current->queue && current->queue->recv_result)
809 reply_message( current->queue, req->result, 0, req->remove );
811 set_error( STATUS_ACCESS_DENIED );
815 /* retrieve the reply for the last message sent */
816 DECL_HANDLER(get_message_reply)
818 if (current->queue) req->result = get_message_reply( current->queue, req->cancel );
819 else set_error( STATUS_ACCESS_DENIED );
823 /* check if we are processing a sent message */
824 DECL_HANDLER(in_send_message)
830 struct message_result *result = current->queue->recv_result;
833 flags |= ISMEX_SEND; /* FIXME */
834 if (result->replied || !result->sender) flags |= ISMEX_REPLIED;
841 /* cleanup a queue when a window is deleted */
842 DECL_HANDLER(cleanup_window_queue)
844 if (current->queue) cleanup_window( current->queue, req->win );
848 /* set a window timer */
849 DECL_HANDLER(set_win_timer)
852 struct msg_queue *queue = get_current_queue();
856 /* remove it if it existed already */
857 if (req->win) kill_timer( queue, req->win, req->msg, req->id );
859 if ((timer = set_timer( queue, req->rate )))
861 timer->win = req->win;
862 timer->msg = req->msg;
864 timer->lparam = req->lparam;
868 /* kill a window timer */
869 DECL_HANDLER(kill_win_timer)
871 struct msg_queue *queue = current->queue;
873 if (!queue || !kill_timer( queue, req->win, req->msg, req->id ))
874 set_error( STATUS_INVALID_PARAMETER );