aboutsummaryrefslogtreecommitdiff
path: root/event.go
blob: 893d5e063a816615c5f0c40423024e6587f50f73 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package salticidae

// #include "salticidae/event.h"
// #include <signal.h>
import "C"
import "runtime"

// The C pointer type for an EventContext handle.
type CEventContext = *C.eventcontext_t
type eventContext struct {
    inner CEventContext
    attached map[uintptr]interface{}
}
// The handle for an event loop.
type EventContext = *eventContext

func NewEventContext() EventContext {
    res := &eventContext{
        inner: C.eventcontext_new(),
        attached: make(map[uintptr]interface{}),
    }
    runtime.SetFinalizer(res, func(self EventContext) { self.free() })
    return res
}

func (self EventContext) attach(ptr rawptr_t, x interface{}) { self.attached[uintptr(ptr)] = x }
func (self EventContext) detach(ptr rawptr_t) { delete(self.attached, uintptr(ptr)) }
func (self EventContext) free() { C.eventcontext_free(self.inner) }

// Start the event loop. This is a blocking call that will hand over the
// control flow to the infinite loop which triggers callbacks upon new events.
// The function will return when Stop() is called.
func (self EventContext) Dispatch() { C.eventcontext_dispatch(self.inner) }

// Stop the event loop. This function is typically called in a callback. Notice
// that all methods of an EventContext should be invoked by the same thread
// which logically owns the loop. To schedule code executed in the event loop
// of a particular thread, see ThreadCall.
func (self EventContext) Stop() { C.eventcontext_stop(self.inner) }

// The C pointer type for a ThreadCall handle.
type CThreadCall = *C.threadcall_t
type threadCall struct { inner CThreadCall }
// The handle for scheduling a function call executed by a particular
// EventContext event loop.
type ThreadCall = *threadCall

// The C function pointer type which takes threadcall_handle_t* and void*
// (passing in the custom user data allocated by C.malloc) as parameters.
type ThreadCallCallback = C.threadcall_callback_t

// Create a ThreadCall handle attached to the given EventContext. Each
// invokcation of AsyncCall() will schedule a function call executed in the
// given EventContext event loop.
func NewThreadCall(ec EventContext) ThreadCall {
    res := &threadCall{ inner: C.threadcall_new(ec.inner) }
    runtime.SetFinalizer(res, func(self ThreadCall) { self.free() })
    return res
}

func (self ThreadCall) free() { C.threadcall_free(self.inner) }

// Schedule a function to be executed in the target event loop.
func (self ThreadCall) AsyncCall(callback ThreadCallCallback, userdata rawptr_t) {
    C.threadcall_async_call(self.inner, callback, userdata)
}

// The C pointer type for TimerEvent handle.
type CTimerEvent = *C.timerev_t
type timerEvent struct {
    inner CTimerEvent
    ec EventContext
}

// The handle for a timed event.
type TimerEvent = *timerEvent

// The C function pointer type which takes timerev_t* (the C pointer to
// TimerEvent) and void* (the unsafe pointer to any userdata) as parameter
type TimerEventCallback = C.timerev_callback_t

// Create a TimerEvent handle attached to the given EventContext, with a
// registered callback.
func NewTimerEvent(_ec EventContext, cb TimerEventCallback, userdata rawptr_t) TimerEvent {
    res := &timerEvent{
        inner: C.timerev_new(_ec.inner, cb, userdata),
        ec: _ec,
    }
    _ec.attach(rawptr_t(res.inner), res)
    runtime.SetFinalizer(res, func(self TimerEvent) { self.free() })
    return res
}

func (self TimerEvent) free() { C.timerev_free(self.inner) }

// Change the callback.
func (self TimerEvent) SetCallback(callback TimerEventCallback, userdata rawptr_t) {
    C.timerev_set_callback(self.inner, callback, userdata)
}

// Schedule the timer to go off after t_sec seconds.
func (self TimerEvent) Add(t_sec float64) { C.timerev_add(self.inner, C.double(t_sec)) }


// Unschedule the timer if it was scheduled. The timer could still be rescheduled
// by calling Add() afterwards.
func (self TimerEvent) Del() {
    self.ec.detach(rawptr_t(self.inner))
    C.timerev_del(self.inner)
}

// Empty the timer. It will be unscheduled and deallocated and its methods
// should never be called again.
func (self TimerEvent) Clear() {
    self.ec.detach(rawptr_t(self.inner))
    C.timerev_clear(self.inner)
}

// The C pointer type for a SigEvent.
type CSigEvent = *C.sigev_t
type sigEvent struct {
    inner CSigEvent
    ec EventContext
}

// The handle for a UNIX signal event.
type SigEvent = *sigEvent

type SigEventCallback = C.sigev_callback_t

var (
    SIGTERM = C.SIGTERM
    SIGINT = C.SIGINT
)

// Create a SigEvent handle attached to the given EventContext, with a
// registered callback.
func NewSigEvent(_ec EventContext, cb SigEventCallback, userdata rawptr_t) SigEvent {
    res := &sigEvent{
        inner: C.sigev_new(_ec.inner, cb, userdata),
        ec: _ec,
    }
    _ec.attach(rawptr_t(res.inner), res)
    runtime.SetFinalizer(res, func(self SigEvent) { self.free() })
    return res
}

func (self SigEvent) free() { C.sigev_free(self.inner) }

// Register the handle to listen for UNIX signal sig.
func (self SigEvent) Add(sig int) { C.sigev_add(self.inner, C.int(sig)) }


// Unregister the handle. The handle may be re-registered in the future.
func (self SigEvent) Del() {
    self.ec.detach(rawptr_t(self.inner))
    C.sigev_del(self.inner)
}

// Unregister the handle. Any methods of the handle should no longer be used
// and the handle will be deallocated.
func (self SigEvent) Clear() {
    self.ec.detach(rawptr_t(self.inner))
    C.sigev_clear(self.inner)
}