2 Copyright (C) 2001-2008, The Perl Foundation.
7 src/events.c - Event handling stuff
11 An event_thread handles async events for all interpreters. When events
12 are due, they are placed in per interpreter task_queues, where they are
13 handled then by the C<check_event*> opcodes.
15 IO events and signals are caught in the io_thread, which again
16 dispatches these to one or all interpreters.
24 #include "parrot/parrot.h"
25 #include "parrot/events.h"
27 typedef struct pending_io_events
{
28 parrot_event
**events
;
33 /* HEADERIZER HFILE: include/parrot/events.h */
34 /* HEADERIZER BEGIN: static */
35 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
37 PARROT_WARN_UNUSED_RESULT
38 PARROT_CAN_RETURN_NULL
39 static opcode_t
* do_event(PARROT_INTERP
,
40 ARGIN(parrot_event
* event
),
41 ARGIN_NULLOK(opcode_t
*next
))
42 __attribute__nonnull__(1)
43 __attribute__nonnull__(2);
46 PARROT_CANNOT_RETURN_NULL
47 static QUEUE_ENTRY
* dup_entry(ARGIN(const QUEUE_ENTRY
*entry
))
48 __attribute__nonnull__(1);
50 PARROT_WARN_UNUSED_RESULT
51 PARROT_CANNOT_RETURN_NULL
52 static QUEUE_ENTRY
* dup_entry_interval(
53 ARGIN(QUEUE_ENTRY
*entry
),
55 __attribute__nonnull__(1);
57 PARROT_WARN_UNUSED_RESULT
58 PARROT_CAN_RETURN_NULL
59 static void* event_thread(ARGMOD(void *data
))
60 __attribute__nonnull__(1)
63 static void event_to_exception(PARROT_INTERP
,
64 ARGIN(const parrot_event
* event
))
65 __attribute__nonnull__(1)
66 __attribute__nonnull__(2);
68 static void init_events_all(PARROT_INTERP
)
69 __attribute__nonnull__(1);
71 static void init_events_first(PARROT_INTERP
)
72 __attribute__nonnull__(1);
74 PARROT_CAN_RETURN_NULL
75 static void* io_thread(SHIM(void *data
));
77 static void io_thread_ready_rd(ARGMOD(pending_io_events
*ios
), int ready_rd
)
78 __attribute__nonnull__(1)
81 static void Parrot_sigaction(int sig
, ARGIN(void (*handler
)(int)))
82 __attribute__nonnull__(2);
84 static void Parrot_unblock_signal(int sig
);
85 static int process_events(ARGMOD(QUEUE
*event_q
))
86 __attribute__nonnull__(1)
87 FUNC_MODIFIES(*event_q
);
89 static void schedule_signal_event(int signum
);
90 static void sig_handler(int signum
);
91 static void stop_io_thread(void);
92 static void store_io_event(
93 ARGMOD(pending_io_events
*ios
),
94 ARGIN(parrot_event
*ev
))
95 __attribute__nonnull__(1)
96 __attribute__nonnull__(2)
99 PARROT_WARN_UNUSED_RESULT
100 PARROT_CAN_RETURN_NULL
101 static opcode_t
* wait_for_wakeup(PARROT_INTERP
,
102 ARGIN_NULLOK(opcode_t
*next
))
103 __attribute__nonnull__(1);
105 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
106 /* HEADERIZER END: static */
109 * event debugging stuff - turn it off before running tests
111 #define EVENT_DEBUG 0
113 * not yet - need to sort out platform code and fix exceptions first
114 * TODO get some config for POSIX compliant
115 * TODO create API for extenders like ponie - events disabled for now
117 #if defined(linux) || defined(darwin)
118 # define INSTALL_EVENT_HANDLER 0
120 # define INSTALL_EVENT_HANDLER 0
124 # define edebug(x) fprintf (x)
125 static const char *ev_names
[] = {
131 "EVENT_TYPE_CALL_BACK",
133 "EVENT_TYPE_TERMINATE",
134 "EVENT_TYPE_EVENT_TERMINATE",
135 "EVENT_TYPE_CLASS_CHANGED",
137 "EVENT_TYPE_SUSPEND_FOR_GC"
140 et(const parrot_event
* const e
)
142 return ev_names
[e
->type
];
153 * we have exactly one global event_queue
154 * TODO task prio handling
156 static QUEUE
*event_queue
;
160 * user accessible signals like SIGINT
163 # define SIGINT -4711
166 # define SIGHUP -4712
170 * XXX need a configure test
171 * should be sig_atomic_t
173 static int sig_int
, sig_hup
;
176 * a pipe is used to send messages to the IO thread
178 static int pipe_fds
[2];
179 #define PIPE_READ_FD pipe_fds[0]
180 #define PIPE_WRITE_FD pipe_fds[1]
183 * a structure to communicate with the io_thread
185 typedef struct io_thread_msg
{
195 =head2 Signal Handling
199 =item C<static void sig_handler>
201 Handle signal C<signum>.
203 TODO - Only C<SIGHUP> is handled at the moment for testing
210 sig_handler(int signum
)
226 =item C<static void Parrot_sigaction>
228 Signal handlers are common to all threads, signal block masks are
229 specific, so we install one handler then block that signal and unblock
230 it in the thread, that will receive that signal.
237 Parrot_sigaction(int sig
, ARGIN(void (*handler
)(int)))
239 #ifdef PARROT_HAS_SIGACTION
240 struct sigaction action
;
243 /* install handler */
244 action
.sa_handler
= handler
;
245 sigemptyset(&action
.sa_mask
);
247 sigaction(sig
, &action
, NULL
);
249 /* block that signal */
250 sigemptyset(&block_mask
);
251 sigaddset(&block_mask
, sig
);
252 sigprocmask(SIG_BLOCK
, &block_mask
, NULL
);
262 =item C<static void Parrot_unblock_signal>
271 Parrot_unblock_signal(int sig
)
273 #ifdef PARROT_HAS_SIGACTION
276 sigemptyset(&block_mask
);
277 sigaddset(&block_mask
, sig
);
278 sigprocmask(SIG_UNBLOCK
, &block_mask
, NULL
);
287 =item C<void Parrot_init_signals>
289 Set up actions to handle signals.
290 Only SIGHUP handled at the moment.
298 Parrot_init_signals(void)
301 * SIGFPE is architecture specific - some signal an error,
302 * some don't, so we have to use direct checks if we are dividing
305 Parrot_sigaction(SIGHUP
, sig_handler
);
312 =head2 Initialization
316 =item C<static void init_events_first>
318 Init event system for first interpreter.
325 init_events_first(PARROT_INTERP
)
327 Parrot_thread ev_handle
;
329 Parrot_thread io_handle
;
333 * be sure all init is done only once
334 * we could use pthread_once for that too
337 PANIC(interp
, "event queue already exists - missing parent_interp?");
341 event_queue
= queue_init(TASK_PRIO
);
343 * we use a message pipe to send IO related stuff to the
348 * pipes on WIN32 don't support select
349 * s. p6i: "event.c - of signals and pipes"
352 real_exception(interp
, NULL
, 1, "Couldn't create message pipe");
355 * now set some sig handlers before any thread is started, so
356 * that all threads inherit the signal block mask
358 #if INSTALL_EVENT_HANDLER
359 Parrot_init_signals();
362 * we start an event_handler thread
364 THREAD_CREATE_DETACHED(ev_handle
, event_thread
, event_queue
);
366 * and a signal and IO handler thread
369 THREAD_CREATE_DETACHED(io_handle
, io_thread
, event_queue
);
375 =item C<static void init_events_all>
377 Init events for all interpreters.
384 init_events_all(PARROT_INTERP
)
387 * create per interpreter task queue
389 interp
->task_queue
= queue_init(0);
394 =item C<void Parrot_init_events>
396 Initialize the event system.
404 Parrot_init_events(PARROT_INTERP
)
406 if (!interp
->parent_interpreter
) {
407 /* add the very first interpreter to the list of interps. */
408 pt_add_to_interpreters(interp
, NULL
);
409 init_events_first(interp
);
411 init_events_all(interp
);
418 =head2 Event Handler Functions
422 =item C<void Parrot_schedule_event>
424 Create queue entry and insert event into task queue.
432 Parrot_schedule_event(PARROT_INTERP
, ARGMOD(parrot_event
* ev
))
434 QUEUE_ENTRY
* const entry
= mem_allocate_typed(QUEUE_ENTRY
);
439 case EVENT_TYPE_TIMER
:
440 case EVENT_TYPE_SLEEP
:
441 entry
->type
= QUEUE_ENTRY_TYPE_TIMED_EVENT
;
442 insert_entry(event_queue
, entry
);
444 case EVENT_TYPE_CALL_BACK
:
445 case EVENT_TYPE_SIGNAL
:
447 entry
->type
= QUEUE_ENTRY_TYPE_EVENT
;
448 unshift_entry(event_queue
, entry
);
451 entry
->type
= QUEUE_ENTRY_TYPE_EVENT
;
452 push_entry(event_queue
, entry
);
459 =item C<static void schedule_signal_event>
461 create and schedule a signal event
468 schedule_signal_event(int signum
)
470 parrot_event
* const ev
= mem_allocate_typed(parrot_event
);
471 QUEUE_ENTRY
* const entry
= mem_allocate_typed(QUEUE_ENTRY
);
474 entry
->type
= QUEUE_ENTRY_TYPE_EVENT
;
475 ev
->type
= EVENT_TYPE_SIGNAL
;
476 ev
->u
.signal
= signum
;
479 * deliver to all interpreters
481 Parrot_schedule_broadcast_qentry(entry
);
486 =item C<void Parrot_new_timer_event>
488 Create a new timer event due at C<diff> from now, repeated at C<interval>
489 and running the passed C<sub>.
497 Parrot_new_timer_event(PARROT_INTERP
, ARGIN_NULLOK(PMC
*timer
), FLOATVAL diff
,
498 FLOATVAL interval
, int repeat
, ARGIN_NULLOK(PMC
*sub
), parrot_event_type_enum typ
)
500 parrot_event
* const ev
= mem_allocate_typed(parrot_event
);
502 const FLOATVAL now
= Parrot_floatval_time();
505 ev
->u
.timer_event
.timer
= timer
;
506 ev
->u
.timer_event
.abs_time
= now
+ diff
;
507 ev
->u
.timer_event
.interval
= interval
;
508 ev
->u
.timer_event
.repeat
= repeat
;
509 ev
->u
.timer_event
.sub
= sub
;
511 if (repeat
&& FLOAT_IS_ZERO(interval
))
512 ev
->u
.timer_event
.interval
= diff
;
514 Parrot_schedule_event(interp
, ev
);
519 =item C<void Parrot_new_cb_event>
521 Prepare and schedule a callback event.
529 Parrot_new_cb_event(PARROT_INTERP
, ARGIN(PMC
*cbi
), ARGIN(char *ext
))
531 parrot_event
* const ev
= mem_allocate_typed(parrot_event
);
532 QUEUE_ENTRY
* const entry
= mem_allocate_typed(QUEUE_ENTRY
);
537 ev
->type
= EVENT_TYPE_CALL_BACK
;
538 ev
->u
.call_back
.cbi
= cbi
;
539 ev
->u
.call_back
.external_data
= ext
;
540 Parrot_schedule_interp_qentry(interp
, entry
);
545 =item C<void Parrot_del_timer_event>
547 Deactivate the timer identified by C<timer>.
555 Parrot_del_timer_event(PARROT_INTERP
, ARGIN(const PMC
*timer
))
559 LOCK(event_queue
->queue_mutex
);
561 for (entry
= event_queue
->head
; entry
; entry
= entry
->next
) {
562 if (entry
->type
== QUEUE_ENTRY_TYPE_TIMED_EVENT
) {
564 parrot_event
* const event
= (parrot_event
*)entry
->data
;
566 if (event
->interp
== interp
567 && event
->u
.timer_event
.timer
== timer
) {
568 event
->u
.timer_event
.interval
= 0.0;
569 event
->type
= EVENT_TYPE_NONE
;
574 UNLOCK(event_queue
->queue_mutex
);
579 =item C<void Parrot_new_terminate_event>
581 Create a terminate event, interpreter will leave the run-loop when this
590 Parrot_new_terminate_event(PARROT_INTERP
)
592 parrot_event
* const ev
= mem_allocate_typed(parrot_event
);
593 ev
->type
= EVENT_TYPE_TERMINATE
;
594 Parrot_schedule_event(interp
, ev
);
599 =item C<void Parrot_new_suspend_for_gc_event>
601 Create a suspend-for-GC event, interpreter will wait on a condition
602 variable for GC to finish when the event arrives.
610 Parrot_new_suspend_for_gc_event(PARROT_INTERP
)
613 parrot_event
* const ev
= mem_allocate_typed(parrot_event
);
614 ev
->type
= EVENT_TYPE_SUSPEND_FOR_GC
;
615 qe
= mem_allocate_typed(QUEUE_ENTRY
);
618 qe
->type
= QUEUE_ENTRY_TYPE_EVENT
;
619 /* we don't use schedule_event because we must modify its
620 * task queue immediately
622 Parrot_schedule_interp_qentry(interp
, qe
);
627 =item C<void Parrot_kill_event_loop>
629 Schedule event-loop terminate event. This shuts down the event thread.
637 Parrot_kill_event_loop(PARROT_INTERP
)
639 parrot_event
* const ev
= mem_allocate_typed(parrot_event
);
640 ev
->type
= EVENT_TYPE_EVENT_TERMINATE
;
641 Parrot_schedule_event(interp
, ev
);
646 =item C<void Parrot_schedule_interp_qentry>
648 Put a queue entry into the interpreters task queue and enable event
649 checking for the interpreter.
657 Parrot_schedule_interp_qentry(PARROT_INTERP
, ARGIN(struct QUEUE_ENTRY
*entry
))
659 parrot_event
* const event
= (parrot_event
*)entry
->data
;
661 * sleep checks events when it awakes
663 edebug((stderr
, "got entry - schedule_inter_qentry %s\n", et(event
)));
664 if (event
->type
!= EVENT_TYPE_SLEEP
)
665 enable_event_checking(interp
);
667 * do push_entry last - this signales the queue condition so the
668 * interpreter might starting process that event immediately
670 * we should better use a priority for placing the event
671 * in front or at the end of the queue
673 switch (event
->type
) {
674 case EVENT_TYPE_CALL_BACK
:
675 case EVENT_TYPE_SIGNAL
:
676 unshift_entry(interp
->task_queue
, entry
);
679 push_entry(interp
->task_queue
, entry
);
686 =item C<void Parrot_schedule_broadcast_qentry>
695 Parrot_schedule_broadcast_qentry(ARGIN(struct QUEUE_ENTRY
*entry
))
697 parrot_event
* const event
= (parrot_event
*)entry
->data
;
699 switch (event
->type
) {
700 case EVENT_TYPE_SIGNAL
:
701 edebug((stderr
, "broadcast signal\n"));
703 * we don't have special signal handlers in usercode yet
705 * install handler like exception handler *and*
706 * set a interpreter flag, that a handler exists
707 * we then could examine that flag (after LOCKing it)
708 * and dispatch the exception to all interpreters that
710 * Finally, we send the first (main) interpreter that signal
712 * For now just send to all.
715 switch (event
->u
.signal
) {
719 if (n_interpreters
) {
721 LOCK(interpreter_array_mutex
);
722 for (i
= 1; i
< n_interpreters
; ++i
) {
724 edebug((stderr
, "deliver SIGINT to %d\n", i
));
725 interp
= interpreter_array
[i
];
727 Parrot_schedule_interp_qentry(interp
,
730 UNLOCK(interpreter_array_mutex
);
732 Parrot_schedule_interp_qentry(interpreter_array
[0], entry
);
733 edebug((stderr
, "deliver SIGINT to 0\n"));
744 internal_exception(1, "Unknown event to broadcast");
753 =head2 IO Thread Handling
765 =item C<static void store_io_event>
767 Stores an event in the event stack. Allocates memory if necessary.
774 store_io_event(ARGMOD(pending_io_events
*ios
), ARGIN(parrot_event
*ev
))
778 ios
->events
= mem_allocate_n_zeroed_typed(ios
->alloced
, parrot_event
*);
780 else if (ios
->n
>= ios
->alloced
) {
782 mem_realloc_n_typed(ios
->events
, ios
->alloced
, parrot_event
*);
784 ios
->events
[ios
->n
++] = ev
;
789 =item C<static void io_thread_ready_rd>
791 Takes a list of pending i/o events and a file descriptor.
792 If the fd is ready to read, the event is removed from the
793 "pending" list and moved to the "scheduled" task queue.
800 io_thread_ready_rd(ARGMOD(pending_io_events
*ios
), int ready_rd
)
804 for (i
= 0; i
< ios
->n
; ++i
) {
805 parrot_event
* const ev
= ios
->events
[i
];
806 PMC
* const pio
= ev
->u
.io_event
.pio
;
807 const int fd
= PIO_getfd(NULL
, pio
);
809 if (fd
== ready_rd
) {
810 /* remove from event list */
813 for (; i
< ios
->n
; ++i
)
814 ios
->events
[i
] = ios
->events
[i
+1];
816 Parrot_schedule_event(ev
->interp
, ev
);
824 =item C<static void* io_thread>
826 The IO thread uses select/poll to handle IO events and signals.
828 It waits on input from the message pipe to insert file descriptors in
835 PARROT_CAN_RETURN_NULL
837 io_thread(SHIM(void *data
))
839 fd_set act_rfds
, act_wfds
;
842 pending_io_events ios
;
847 /* remember pending io events */
852 * Watch the reader end of the pipe for messages
854 FD_SET(PIPE_READ_FD
, &act_rfds
);
855 n_highest
= PIPE_READ_FD
+ 1;
857 * all signals that we shall handle here have to be unblocked
858 * in this and only in this thread
860 Parrot_unblock_signal(SIGHUP
);
862 fd_set rfds
= act_rfds
;
863 fd_set wfds
= act_wfds
;
864 const int retval
= select(n_highest
, &rfds
, &wfds
, NULL
, NULL
);
868 if (errno
== EINTR
) {
869 edebug((stderr
, "select EINTR\n"));
871 edebug((stderr
, "int arrived\n"));
874 * signal the event thread
876 schedule_signal_event(SIGINT
);
879 edebug((stderr
, "int arrived\n"));
882 * signal the event thread
884 schedule_signal_event(SIGHUP
);
889 case 0: /* timeout - can't happen */
892 edebug((stderr
, "IO ready\n"));
893 for (i
= 0; i
< n_highest
; ++i
) {
894 if (FD_ISSET(i
, &rfds
)) {
895 if (i
== PIPE_READ_FD
) {
900 edebug((stderr
, "msg arrived\n"));
901 if (read(PIPE_READ_FD
, &buf
, sizeof (buf
)) != sizeof (buf
))
902 internal_exception(1,
903 "read error from msg pipe");
904 switch (buf
.command
) {
905 case IO_THR_MSG_TERMINATE
:
908 case IO_THR_MSG_ADD_SELECT_RD
:
910 PMC
* const pio
= buf
.ev
->u
.io_event
.pio
;
911 const int fd
= PIO_getfd(NULL
, pio
);
912 if (FD_ISSET(fd
, &act_rfds
)) {
913 mem_sys_free(buf
.ev
);
916 FD_SET(fd
, &act_rfds
);
919 store_io_event(&ios
, buf
.ev
);
924 internal_exception(1,
925 "unhandled msg in pipe");
932 * one of the io_event fds is ready
933 * remove from active set, as we don't
934 * want to fire again during io_handler
937 FD_CLR(i
, &act_rfds
);
938 io_thread_ready_rd(&ios
, i
);
946 edebug((stderr
, "IO thread terminated\n"));
948 close(PIPE_WRITE_FD
);
955 =item C<static void stop_io_thread>
957 Tell the IO thread to stop.
969 * tell IO thread to stop
971 memset(&buf
, 0, sizeof (buf
));
972 buf
.command
= IO_THR_MSG_TERMINATE
;
973 if (write(PIPE_WRITE_FD
, &buf
, sizeof (buf
)) != sizeof (buf
))
974 internal_exception(1, "msg pipe write failed");
980 =item C<void Parrot_event_add_io_event>
982 Create new i/o event.
990 Parrot_event_add_io_event(PARROT_INTERP
,
991 ARGIN_NULLOK(PMC
*pio
), ARGIN_NULLOK(PMC
*sub
), ARGIN_NULLOK(PMC
*data
), INTVAL which
)
994 parrot_event
* const event
= mem_allocate_typed(parrot_event
);
996 event
->type
= EVENT_TYPE_IO
;
997 event
->interp
= interp
;
999 * TODO dod_register these PMCs as long as the event system
1001 * unregister, when event is passed to interp again
1003 event
->u
.io_event
.pio
= pio
;
1004 event
->u
.io_event
.handler
= sub
;
1005 event
->u
.io_event
.user_data
= data
;
1007 buf
.command
= which
;
1009 /* XXX Why isn't this entire function inside an ifndef WIN32? */
1011 if (write(PIPE_WRITE_FD
, &buf
, sizeof (buf
)) != sizeof (buf
))
1012 real_exception(interp
, NULL
, 1, "msg pipe write failed");
1021 =head2 Event Handler Thread Functions
1025 =item C<static QUEUE_ENTRY* dup_entry>
1027 Duplicate queue entry.
1034 PARROT_CANNOT_RETURN_NULL
1036 dup_entry(ARGIN(const QUEUE_ENTRY
*entry
))
1038 QUEUE_ENTRY
* const new_entry
= mem_allocate_typed(QUEUE_ENTRY
);
1040 new_entry
->next
= NULL
;
1041 new_entry
->type
= entry
->type
;
1042 new_entry
->data
= mem_allocate_typed(parrot_event
);
1044 mem_sys_memcopy(new_entry
->data
, entry
->data
, sizeof (parrot_event
));
1050 =item C<static QUEUE_ENTRY* dup_entry_interval>
1052 Duplicate timed entry and add interval to C<abs_time>.
1058 PARROT_WARN_UNUSED_RESULT
1059 PARROT_CANNOT_RETURN_NULL
1061 dup_entry_interval(ARGIN(QUEUE_ENTRY
*entry
), FLOATVAL now
)
1063 QUEUE_ENTRY
* const new_entry
= dup_entry(entry
);
1064 parrot_event
* const event
= (parrot_event
*)new_entry
->data
;
1066 event
->u
.timer_event
.abs_time
= now
+ event
->u
.timer_event
.interval
;
1073 =item C<static int process_events>
1075 Do something, when an event arrived caller has locked the mutex returns
1076 0 if event thread terminates.
1083 process_events(ARGMOD(QUEUE
*event_q
))
1088 while ((entry
= peek_entry(event_q
)) != NULL
) {
1090 * one or more entries arrived - we hold the mutex again
1091 * so we have to use the nonsyc_pop_entry to pop off event entries
1093 parrot_event
*event
= NULL
;
1095 switch (entry
->type
) {
1096 case QUEUE_ENTRY_TYPE_EVENT
:
1097 entry
= nosync_pop_entry(event_q
);
1098 event
= (parrot_event
*)entry
->data
;
1101 case QUEUE_ENTRY_TYPE_TIMED_EVENT
:
1102 event
= (parrot_event
*)entry
->data
;
1103 now
= Parrot_floatval_time();
1106 * if the timer_event isn't due yet, ignore the event
1107 * (we were signalled on insert of the event)
1108 * wait until we get at it again when time has elapsed
1110 if (now
< event
->u
.timer_event
.abs_time
)
1112 entry
= nosync_pop_entry(event_q
);
1114 /* if event is repeated dup and reinsert it */
1116 if (event
->u
.timer_event
.interval
) {
1117 if (event
->u
.timer_event
.repeat
) {
1118 if (event
->u
.timer_event
.repeat
!= -1)
1119 event
->u
.timer_event
.repeat
--;
1120 nosync_insert_entry(event_q
,
1121 dup_entry_interval(entry
, now
));
1126 internal_exception(1, "Unknown queue entry");
1128 PARROT_ASSERT(event
);
1129 if (event
->type
== EVENT_TYPE_NONE
) {
1130 mem_sys_free(entry
);
1131 mem_sys_free(event
);
1134 else if (event
->type
== EVENT_TYPE_EVENT_TERMINATE
) {
1135 mem_sys_free(entry
);
1136 mem_sys_free(event
);
1141 * now insert entry in interpreter task queue
1143 if (event
->interp
) {
1144 Parrot_schedule_interp_qentry(event
->interp
, entry
);
1147 Parrot_schedule_broadcast_qentry(entry
);
1149 } /* while events */
1155 =item C<static void* event_thread>
1157 The event thread is started by the first interpreter. It handles all
1158 events for all interpreters.
1164 PARROT_WARN_UNUSED_RESULT
1165 PARROT_CAN_RETURN_NULL
1167 event_thread(ARGMOD(void *data
))
1169 QUEUE
* const event_q
= (QUEUE
*) data
;
1172 LOCK(event_q
->queue_mutex
);
1174 * we might already have an event in the queue
1176 if (peek_entry(event_q
))
1177 running
= process_events(event_q
);
1179 QUEUE_ENTRY
* const entry
= peek_entry(event_q
);
1182 /* wait infinite until entry arrives */
1183 queue_wait(event_q
);
1185 else if (entry
->type
== QUEUE_ENTRY_TYPE_TIMED_EVENT
) {
1186 /* do a_timedwait for entry */
1187 struct timespec abs_time
;
1188 parrot_event
* const event
= (parrot_event
*)entry
->data
;
1189 const FLOATVAL when
= event
->u
.timer_event
.abs_time
;
1191 abs_time
.tv_sec
= (time_t) when
;
1192 abs_time
.tv_nsec
= (long)((when
- abs_time
.tv_sec
)*1000.0f
)
1194 queue_timedwait(event_q
, &abs_time
);
1197 /* we shouldn't get here probably
1199 internal_exception(1, "Spurious event");
1203 * one or more entries arrived - we hold the mutex again
1204 * so we have to use the nonsync_pop_entry to pop off event entries
1206 running
= process_events(event_q
);
1209 * the main interpreter is dying
1210 * TODO empty the queue
1212 UNLOCK(event_q
->queue_mutex
);
1213 queue_destroy(event_q
);
1215 edebug((stderr
, "event thread stopped\n"));
1223 =head2 Sleep Handling
1227 =item C<static opcode_t * wait_for_wakeup>
1229 Sleep on the event queue condition. If an event arrives, the event
1230 is processed. Terminate the loop if sleeping is finished.
1236 PARROT_WARN_UNUSED_RESULT
1237 PARROT_CAN_RETURN_NULL
1239 wait_for_wakeup(PARROT_INTERP
, ARGIN_NULLOK(opcode_t
*next
))
1241 QUEUE
* const tq
= interp
->task_queue
;
1243 interp
->sleeping
= 1;
1246 * event handler like callbacks or timers are run as normal code
1247 * so inside such an event handler function, another event might get
1248 * handled, which is good (higher priority events can interrupt
1249 * other event handler). OTOH we must ensure that all state changes
1250 * are done in do_event and we should probably suspend nested
1251 * event handlers sometimes
1253 * FIXME: the same is true for the *next param:
1254 * get rid of that, instead mangle the resume flags
1255 * and offset to stop the runloop
1259 while (interp
->sleeping
) {
1260 QUEUE_ENTRY
* const entry
= wait_for_entry(tq
);
1261 parrot_event
* const event
= (parrot_event
*)entry
->data
;
1263 mem_sys_free(entry
);
1264 edebug((stderr
, "got ev %s head : %p\n", et(event
), tq
->head
));
1265 next
= do_event(interp
, event
, next
);
1268 edebug((stderr
, "woke up\n"));
1274 =item C<opcode_t * Parrot_sleep_on_event>
1276 Go to sleep. This is called from the C<sleep> opcode.
1283 PARROT_WARN_UNUSED_RESULT
1284 PARROT_CAN_RETURN_NULL
1286 Parrot_sleep_on_event(PARROT_INTERP
, FLOATVAL t
, ARGIN_NULLOK(opcode_t
*next
))
1288 #if PARROT_HAS_THREADS
1290 if (interp
->sleeping
)
1291 fprintf(stderr
, "nested sleep might not work\n");
1293 * place the opcode_t* next arg in the event data, so that
1294 * we can identify this event in wakeup
1296 Parrot_new_timer_event(interp
, (PMC
*) next
, t
,
1297 0, 0, NULL
, EVENT_TYPE_SLEEP
);
1298 next
= wait_for_wakeup(interp
, next
);
1301 * TODO check for nanosleep or such
1303 Parrot_sleep((UINTVAL
) ceil(t
));
1312 =head2 Event Handling for Run-Loops
1316 =item C<opcode_t * Parrot_do_check_events>
1318 Explicitly C<sync> called by the check_event opcode from run loops.
1325 PARROT_WARN_UNUSED_RESULT
1326 PARROT_CAN_RETURN_NULL
1328 Parrot_do_check_events(PARROT_INTERP
, ARGIN_NULLOK(opcode_t
*next
))
1330 if (peek_entry(interp
->task_queue
))
1331 return Parrot_do_handle_events(interp
, 0, next
);
1338 =item C<static void event_to_exception>
1340 Convert event to exception and throw it.
1347 event_to_exception(PARROT_INTERP
, ARGIN(const parrot_event
* event
))
1349 const int exit_code
= -event
->u
.signal
;
1351 switch (event
->u
.signal
) {
1355 * SIGINT is silent, if no exception handler is
1356 * installed: set severity to EXCEPT_exit
1358 do_exception(interp
, EXCEPT_exit
, exit_code
);
1361 do_exception(interp
, EXCEPT_error
, exit_code
);
1368 =item C<static opcode_t * do_event>
1370 Run user code or such. The C<event> argument is freed after execution.
1372 TODO: Instrument with splint args so splint knows event gets released.
1378 PARROT_WARN_UNUSED_RESULT
1379 PARROT_CAN_RETURN_NULL
1381 do_event(PARROT_INTERP
, ARGIN(parrot_event
* event
), ARGIN_NULLOK(opcode_t
*next
))
1383 edebug((stderr
, "do_event %s\n", et(event
)));
1384 switch (event
->type
) {
1385 case EVENT_TYPE_TERMINATE
:
1386 next
= NULL
; /* this will terminate the run loop */
1388 case EVENT_TYPE_SIGNAL
:
1389 interp
->sleeping
= 0;
1390 /* generate exception */
1391 event_to_exception(interp
, event
);
1392 /* not reached - will longjmp */
1394 case EVENT_TYPE_TIMER
:
1395 /* run ops, save registers */
1396 Parrot_runops_fromc_args_event(interp
,
1397 event
->u
.timer_event
.sub
, "v");
1399 case EVENT_TYPE_CALL_BACK
:
1400 edebug((stderr
, "starting user cb\n"));
1401 Parrot_run_callback(interp
, event
->u
.call_back
.cbi
,
1402 event
->u
.call_back
.external_data
);
1405 edebug((stderr
, "starting io handler\n"));
1406 Parrot_runops_fromc_args_event(interp
,
1407 event
->u
.io_event
.handler
,
1409 event
->u
.io_event
.pio
,
1410 event
->u
.io_event
.user_data
);
1412 case EVENT_TYPE_SLEEP
:
1413 interp
->sleeping
= 0;
1415 case EVENT_TYPE_SUSPEND_FOR_GC
:
1416 edebug((stderr
, "suspend for gc\n"));
1417 pt_suspend_self_for_gc(interp
);
1420 fprintf(stderr
, "Unhandled event type %d\n", (int)event
->type
);
1423 mem_sys_free(event
);
1429 =item C<opcode_t * Parrot_do_handle_events>
1431 Called by the C<check_event__> opcode from run loops or from above. When
1432 called from the C<check_events__> opcode, we have to restore the
1440 PARROT_WARN_UNUSED_RESULT
1441 PARROT_CAN_RETURN_NULL
1443 Parrot_do_handle_events(PARROT_INTERP
, int restore
, ARGIN_NULLOK(opcode_t
*next
))
1445 QUEUE
* const tq
= interp
->task_queue
;
1448 disable_event_checking(interp
);
1450 if (!peek_entry(tq
))
1453 while (peek_entry(tq
)) {
1454 QUEUE_ENTRY
* const entry
= pop_entry(tq
);
1455 parrot_event
* const event
= (parrot_event
*)entry
->data
;
1457 mem_sys_free(entry
);
1458 next
= do_event(interp
, event
, next
);
1470 F<include/parrot/events.h> and F<docs/dev/events.pod>.
1479 * c-file-style: "parrot"
1481 * vim: expandtab shiftwidth=4: