2 <html><head><meta charset=
"utf-8"><title>Event-driven Programming in Perl
</title><link rel=
"stylesheet" href=
"css/common.css"><link rel=
"stylesheet" href=
"css/slides.css"></head><body><textarea id=
"source">
7 # Event-driven Programming in Perl
12 - Hi. I'm Charles McGarvey.
13 - Been a Perl programmer for a long time...
20 - My employer is hiring.
21 - It's a pretty cool employer...
24 ## "Normal" [userspace] programs
30 4. Write results as output.
35 background-image: url(img/pizza.jpg)
40 # orderpizza --crust-type=thin \
41 --toppings=cheese,pepperoni,mushrooms
46 # source code of the orderpizza program
48 my $order = get_order_from_args(@ARGV);
50 my $ingredients = gather_ingredients($order);
52 my $pizza = prepare_and_bake($order, $ingredentials);
58 ## Event-driven programs
62 2. When events happen, some code runs and does something.
66 At it's core, event-driven programming is this simple.
68 But there are some complications and things to knows, which is why this talk exists.
73 ![Event loop](img/eventloop.svg)
76 We'll refine this model as we go.
79 class: ex-hwinterrupts
81 ## Hardware interrupts
84 # cat /proc/interrupts
86 0:
51 0 IR-IO-APIC
2-edge timer
87 1:
685006 5 IR-IO-APIC
1-edge i8042
88 8:
0 0 IR-IO-APIC
8-edge rtc0
89 9:
1724419 6314 IR-IO-APIC
9-fasteoi acpi
90 12:
12300601 138 IR-IO-APIC
12-edge i8042
91 16:
0 0 IR-IO-APIC
16-fasteoi i801_smbus
92 120:
0 0 DMAR-MSI
0-edge dmar0
93 121:
0 0 DMAR-MSI
1-edge dmar1
94 122:
7009890 45112 IR-PCI-MSI
327680-edge xhci_hcd
95 123:
44 3 IR-PCI-MSI
360448-edge mei_me
96 124:
509 0 IR-PCI-MSI
1048576-edge rtsx_pci
97 125:
80130 0 IR-PCI-MSI
2621440-edge nvme0q0, nvme0q1
98 126:
121892439 2961357 IR-PCI-MSI
32768-edge i915
99 127:
49 100 IR-PCI-MSI
514048-edge snd_hda_intel:card0
100 128:
0 79412 IR-PCI-MSI
2621441-edge nvme0q2
106 When a HW interrupt happens, the appropriate code to run is locate in the interrupt service routine
111 ## Your first event-driven program
115 print "Press
<Enter> to continue.";
118 handle_enter_keypress_event();
125 ## Your first event-driven program
129 print "Press
<Enter> to continue.";
132 handle_enter_keypress_event();
143 ## Your first event-driven program
147 print "Press
<Enter> to continue.";
150 handle_enter_keypress_event();
162 ## Your first event-driven program
166 print "Press
<Enter> to continue.";
169 *handle_enter_keypress_event();
187 $SIG{USR1} = sub { handle_usr1_signal_event() };
188 $SIG{ALRM} = sub { handle_timer_event() };
189 $SIG{QUIT} = sub { exit() };
193 while (
1) { POSIX::pause() }
204 *$SIG{USR1} = sub { handle_usr1_signal_event() };
205 *$SIG{ALRM} = sub { handle_timer_event() };
206 *$SIG{QUIT} = sub { exit() };
210 while (
1) { POSIX::pause() }
214 Notice that this program is capable of handling more than just one event handler at a time.
224 $SIG{USR1} = sub { handle_usr1_signal_event() };
225 $SIG{ALRM} = sub { handle_timer_event() };
226 $SIG{QUIT} = sub { exit() };
230 *while (
1) { POSIX::pause() }
234 - Program yields time to the kernel
238 This example has a loop, but it's not really doing anything.
240 But actually it is doing something very important: It's yielding its processing time to the kernel.
242 And kernel informs the program of events.
244 You might be able to use `sleep` as well, but some implementations of libc
245 in the past have implemented `sleep` using `alarm`.
247 Don't know how common that is nowadays, but old habbits...
252 ## Graphical user interface example
257 my $window = Gtk3::Window-
>new;
259 $window-
>signal_connect('key-press-event' =
> \&handle_keypress_event);
260 $window-
>signal_connect('delete-event' =
> \&Gtk3::main_quit);
268 A user interface happens to be a good place to use evented code because humans are spontaneous and unpredictable.
273 ## Graphical user interface example
278 my $window = Gtk3::Window-
>new;
280 *$window-
>signal_connect('key-press-event' =
> \&handle_keypress_event);
281 *$window-
>signal_connect('delete-event' =
> \&Gtk3::main_quit);
295 ## Graphical user interface example
300 my $window = Gtk3::Window-
>new;
302 $window-
>signal_connect('key-press-event' =
> \&handle_keypress_event);
303 $window-
>signal_connect('delete-event' =
> \&Gtk3::main_quit);
312 - Yield and wait for events
323 Data available on a socket, or a new connection.
325 Server or client, data across a wire cannot typically be relied upon to arrive in a predictable fashion, so an
326 event-driven architect makes a lot of sense for network applications.
332 As far as my program is concerned, it can receive a signal or message from another program at any time.
338 If I need something to happen to happen in five minutes or at a specific absolute time, using the idea of an alarm clock
339 is tempting. I can set an alarm and pretend that the clock itself is a source of events.
345 Human beings of course are masters of spontaneity.
347 Are they going to press a button on the keyboard next, or move the mouse? If my program is connected to a microphone,
348 maybe the human is going to start talking to the program. The program has to be ready for anything, so defining and
349 accepting "events" for all the different ways that a human can interact with the program is a good way to go.
352 - Anything that can happen spontaneously in the real world.
355 Lots of other external systems (besides humans) can "generate" events.
357 Lot of this requires kernel facilities. Speaking of which, how are these types of things implemented?
362 ## How event-driven userspace code works
366 - [`pause`](http://man.he.net/man2/pause) - Sleeps until signal
367 - [`select`](http://man.he.net/man2/select), [`poll`](http://man.he.net/man2/poll), [`epoll`](http://man.he.net/man7/epoll), [`kqueue`](https://www.freebsd.org/cgi/man.cgi?format=ascii&sektion=
2&query=kqueue) - Monitor multiple file descriptors
368 - [`clock_gettime`](http://man.he.net/man2/clock_gettime) - What time is it now?
371 class: ex-basicreactor
377 our $io_handles = [...];
380 my $next_timer = find_next_timer($timers);
382 poll($io_handles, $next_timer-
>time_from_now);
384 handle_ready_io_handles($io_handles);
385 handle_expired_timers($timers);
391 ## Reactor examples on CPAN
394 - [`POE::Loop::IO_Poll`](https://metacpan.org/source/POE::Loop::IO_Poll)
395 - [`POE::Loop::Select`](https://metacpan.org/source/POE::Loop::Select)
396 - [`AnyEvent::Loop`](https://metacpan.org/source/AnyEvent::Loop)
397 - [`IO::Async::Loop::Poll`](https://metacpan.org/source/IO::Async::Loop::Poll)
398 - [`IO::Async::Loop::Select`](https://metacpan.org/source/IO::Async::Loop::Select)
399 - [`Mojo::Reactor::Poll`](https://metacpan.org/source/Mojo::Reactor::Poll)
403 class: center, middle
411 class: center, middle
416 </textarea><script src=
"https://gnab.github.io/remark/downloads/remark-latest.min.js"></script><script>var slideshow = remark.create({countIncrementalSlides: true, highlightLanguage: '', highlightLines: true, highlightStyle: 'hybrid', ratio: '
16:
9', /*slideNumberFormat: '',*/ navigation: {scroll: false, touch: false, click: false}})
</script><script src=
"js/common.js"></script><script src=
"js/slides.js"></script></body></html>
417 <!-- vim: set ts=4 sts=4 sw=4 tw=120 et ft=markdown nowrap: -->