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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
Centralized events loops
========================
[green threads, if feasible to implement, would be a lot easier to use...]
It would be nice to have some kind of centralized event loop.
Requirements:
* Multiple places of one linkage unit may need to get events
* Multiple places of one application (executable + libraries)
may need to get events.
* Different types of events need to be possible to register:
- files
- sockets
- timers
(- signals)
- internal events
- system specific events (like window messages on Windows)
* Unrelated events should be isolated from event handlers
that shouldn't see them.
* An event handler should be able to look ahead and priotize
events internally.
* Events from different sources need to be handled in a round
robin way, but some may have higher priority in terms of
fraction of requests or fraction of time.
* Events related to the same object (e.g. a socket) should
generally not happen in parallel (except possibly for incoming
connections)
Events may have some special syntax, but there also needs to be an API
in some kind of SLUL runtime library. The API should not be locked to
any specific type of event handling (polling, ring buffer, etc).
At startup of a program it should be possible to request a specific
implementation. If no request is made, the runtime library should
lazilly select some good all-round implementation.
API idea
--------
Internal API:
Each module that uses events exposes a function:
func MODNAME_event_wakeup(ref EventCtx evctx)
The runtime library exposes a set of internal functions:
## Creates an event context
func .new() -> ref var own EventPool
func EventPool.subsc_file(ref grab var File file) var -> ref grab(file) EventTicket or Error
func EventPool.subsc_socket(ref grab var Socket sock) var -> ref grab(sock) EventTicket or Error
func EventPool.subsc_timer(ref grab var Timer timer) var -> ref grab(timer) EventTicket or Error
func EventPool.unsubsc_file(ref release var File file, ref grab(file) EventTicket ticket) var
func EventPool.unsubsc_socket(ref release var Socket sock, ref grab(sock) EventTicket ticket) var
func EventPool.unsubsc_timer(ref release var Timer timer, ref grab(timer) EventTicket ticket) var
## Synchronizes all changes to the EventCtx
func EventPool.sync() var
## Waits for events in a loop
func EventPool.loop() var
func EventPool.free() var own
Try 2:
## Creates an event context
func .new() -> ref var own EventPool
# ticket is a special 0-byte type. It has only one value, which is 1.
# tickets must eventually be returned.
func EventPool.subsc_file(grabref var File file, ref T prm) var -> ticket(file) or Error
func EventPool.subsc_single_socket(grabref var Socket sock, ref T prm) var -> ticket(sock) or Error
func EventPool.subsc_connections(grabref var Socket sock, ref T prm) var -> ticket(sock) or Error
func EventPool.subsc_timer(grabref var Timer timer, ref T prm) var -> ticket(timer) or Error
func EventPool.unsubsc_file(releaseref var File file, ticket(file) t) var
func EventPool.unsubsc_single_socket(releaseref var Socket sock, ticket(sock) t) var
func EventPool.unsubsc_connections(releaseref var Socket sock, ticket(sock) t) var
func EventPool.unsubsc_timer(releaseref var Timer timer, ticket(timer) t) var
## Synchronizes all changes to the EventPool.
## This happens automatically when calling (or returning to) the loop function.
func EventPool.sync() var
## Waits for events in a loop
func EventPool.loop() var
func EventPool.free() var own
...
High level API example:
event .ready(grabref SecureSocket server) -> ref own var ServerState
{
...
}
event ServerState.start_failed(ref SecureSocket server) static
{
...
}
event ServerState.shutting_down()
{
...
}
event ServerState.got_conn(ref SecureSocket server) -> ref own var Connection
{
own var Connection conn = .new()
conn.socket = server.accept(Connection)
...
return conn
}
event Connection.closed_conn() own var
{
...
}
event Connection.has_data()
{
...
}
event Connection.can_send()
{
...
}
type ConfigData = struct {
string main_cfg
List<string> dir_cfg
}
type Server = struct {
own var WaitAll<Server> wait
own var threaded ConfigData cfg
}
func .new() -> own var Server
{
own var Server server = .new()
server.wait = .wait(server)
...
return server
}
event Server.wait_done()
{
# TODO how to handle out of memory?
# Asynchronously creates a socket and reads system truststores
#own SecureSocket ssock = .new(.listen_local(80, ServerState))
server.tls_sock = .new(.listen_local(80, ServerState))
}
func start_server() -> own var Server
{
own var ConfigData cfg = .new()
# server takes ownership of cfg, but cfg is implictly grabbed
# by this function, because it uses cfg
own var Server server = .new(cfg)
# wait grabs server
#own var WaitAll wait = .new(server)
server.wait.add(File.open("/etc/myserver/config.cfg").contents_to_string(@cfg.main_cfg))
server.wait.add(File.list("/etc/myserver/config.d/*.conf").add_to_list(@cfg.dir_cfg,
lambda (File f, Slot<String> entry) -> f.open().contents_to_slot(entry))
server.wait.start(server)
# cfg is ungrabbed
return server
}
It would be cool if we could write:
func start_server() -> own var Server
{
own var ConfigData cfg = .new()
own var Server server = .new(cfg)
async {
File.open("/etc/myserver/config.cfg").contents_to_string(@cfg.main_cfg)
File.list("/etc/myserver/config.d/*.conf").add_to_list(@cfg.dir_cfg,
lambda (File f, Slot<String> entry) -> f.open().contents_to_slot(entry)
} after {
server.tls_sock = .new(.listen_local(80, ServerState))
}
return server
}
|