1 /*
2  * Geario - A cross-platform abstraction library with asynchronous I/O.
3  *
4  * Copyright (C) 2021-2022 Kerisy.com
5  *
6  * Website: https://www.kerisy.com
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module geario.event.timer.Epoll;
13 
14 // dfmt off
15 version (HAVE_EPOLL) : 
16 // dfmt on
17 
18 import geario.event.selector.Selector;
19 import geario.event.timer.Common;
20 import geario.Functions;
21 import geario.net.channel.Types;
22 
23 import core.sys.posix.unistd;
24 import core.sys.posix.time : itimerspec, CLOCK_MONOTONIC;
25 
26 import core.time;
27 import std.socket;
28 
29 /**
30 */
31 abstract class AbstractTimer : TimerChannelBase {
32     this(Selector loop) {
33         super(loop);
34         init();
35     }
36 
37     private void init() {
38         setFlag(ChannelFlag.Read, true);
39         _readBuffer = new UintObject();
40         this.handle = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
41         // setTimer();
42     }
43 
44     ~this() @nogc {
45         // Close();
46     }
47 
48     private bool setTimer() {
49         itimerspec its;
50         ulong sec, nsec;
51         sec = time() / 1000;
52         nsec = (time() % 1000) * 1_000_000;
53 
54         its.it_value.tv_sec = cast(typeof(its.it_value.tv_sec)) sec;
55         its.it_value.tv_nsec = cast(typeof(its.it_value.tv_nsec)) nsec;
56         its.it_interval.tv_sec = its.it_value.tv_sec;
57         its.it_interval.tv_nsec = its.it_value.tv_nsec;
58         const int err = timerfd_settime(this.handle, 0, &its, null);
59         if (err == -1) {
60             return false;
61         }
62         return true;
63     }
64 
65     bool readTimer(scope SimpleActionHandler read) {
66         this.ClearError();
67         uint value;
68         core.sys.posix.unistd.read(this.handle, &value, 8);
69         this._readBuffer.data = value;
70         if (read)
71             read(this._readBuffer);
72         return false;
73     }
74 
75     override void Start(bool immediately = false, bool once = false) {
76         setTimer();
77         super.Start();
78     }
79 
80     UintObject _readBuffer;
81 }
82 
83 /**
84 C APIs for timerfd
85 */
86 enum TFD_TIMER_ABSTIME = 1 << 0;
87 enum TFD_CLOEXEC = 0x80000;
88 enum TFD_NONBLOCK = 0x800;
89 
90 extern (C) {
91     socket_t timerfd_create(int clockid, int flags) nothrow;
92     int timerfd_settime(int fd, int flags, const itimerspec* new_value, itimerspec* old_value) nothrow;
93     int timerfd_gettime(int fd, itimerspec* curr_value) nothrow;
94 }