Skip to content

Commit 4a3f7c7

Browse files
authored
Merge pull request #50 from ferus-web/graceful-exits
Graceful exit support
2 parents b37e65e + 2cf93c5 commit 4a3f7c7

File tree

9 files changed

+65
-10
lines changed

9 files changed

+65
-10
lines changed

ferus.nimble

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ bin = @["ferus", "ferus_process"]
1313
requires "nim >= 2.0.2"
1414
requires "ferusgfx >= 1.2.1"
1515
requires "colored_logger >= 0.1.0"
16-
requires "stylus#master"
16+
requires "stylus >= 0.1.3"
1717
requires "https://github.com/ferus-web/sanchar >= 2.0.2"
1818
requires "https://git.sr.ht/~bptato/chame >= 1.0.1"
1919
requires "seccomp >= 0.2.1"
2020
requires "simdutf >= 5.5.0"
21-
requires "https://github.com/ferus-web/bali >= 0.6.3"
21+
requires "https://github.com/ferus-web/bali#master"
2222
requires "results >= 0.5.0"
2323
requires "pretty >= 0.1.0"
2424
requires "jsony >= 1.1.5"

src/bindings/yoga.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ static:
1818
echo pwd
1919

2020
{.passC: "-I" & gorge("pwd") & "/install/include".}
21-
{.passL: "-L" & gorge("pwd") & "/install/lib64 -lyogacore".}
21+
{.passL: "-L" & gorge("pwd") & "/install/lib -lyogacore".}
2222

2323
{.push header: "<yoga/Yoga.h>".}
2424
type

src/components/ipc/shared.nim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,8 @@ proc magicFromStr*(s: string): Option[FerusMagic] =
395395
return some feJSTakeDocument
396396
of "feRendererExit":
397397
return some feRendererExit
398+
of "feGoodbye":
399+
return some feGoodbye
398400
else:
399401
warn "magicFromStr(" & s & "): no such magic string found."
400402

src/components/js/process.nim

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type JSProcess* = object
1515
ipc*: IPCClient
1616
parser*: Parser
1717
runtime*: Runtime
18+
running*: bool = true
1819

1920
document*: HTMLDocument
2021

@@ -72,6 +73,14 @@ proc talk(js: var JSProcess, process: FerusProcess) =
7273

7374
debug "Got document for this tab - passing it to JS land."
7475
js.document = packet.document
76+
of feGoodbye:
77+
info "js: got goodbye packet, cleaning up."
78+
# TODO: make it so that we always respond to goodbye(s), even when in an unreachable/expensive VM loop
79+
# there's two ways to do this:
80+
# a) either add a way for a hook function to constantly monitor for this packet (bad performance)
81+
# b) shift the VM to another thread (good performance but harder to work with)
82+
js.runtime.vm.halt = true
83+
js.running = false
7584
else:
7685
discard
7786

@@ -87,5 +96,5 @@ proc jsProcessLogic*(client: var IPCClient, process: FerusProcess) {.inline.} =
8796
else:
8897
setLogFilter(lvlNone)
8998

90-
while true:
99+
while js.running:
91100
js.talk(process)

src/components/master/master.nim

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## The IPC "master". This is just an abstraction over the IPC server.
2+
## It essentially allows you to do anything with your own group of processes (renderer, JS runtime, CSS/HTML parsers, etc.)
3+
## This includes summoning them, telling them to do a task, telling them to exit, et cetera.
4+
15
import
26
std/
37
[os, logging, osproc, strutils, options, base64, net, sets, terminal, posix, tables]
@@ -25,6 +29,8 @@ type MasterProcess* = ref object
2529
server*: IPCServer
2630
urls*: Table[uint, URL]
2731

32+
alive*: bool = true
33+
2834
proc initialize*(master: MasterProcess) {.inline.} =
2935
master.server.add(FerusGroup())
3036
# TODO: multi-tab support, although we could just keep adding more FerusGroup(s) and it should *theoretically* scale
@@ -515,8 +521,20 @@ proc packetHandler*(
515521
master.server.reportBadMessage(
516522
process, "Non-renderer process sent `feRendererExit` opcode", High
517523
)
524+
return
525+
526+
info "The renderer has shut down. Beginning cleanup."
527+
528+
# Here, we start sending "goodbye" packets to all processes.
529+
# We're essentially telling them, "Hey, start cleaning up and die."
530+
for i, group in master.server.groups:
531+
for process in group:
532+
debug "Telling PID " & $process.pid & " (group " & $i & "'s " & $process.kind &
533+
") to exit"
534+
master.server.send(process.socket, GoodbyePacket())
518535

519-
debug "The renderer has shut down."
536+
info "Cleanup completed. Adios!"
537+
master.alive = false
520538
else:
521539
warn "Unhandled IPC protocol magic: " & $kind
522540
return

src/components/network/process.nim

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,17 @@ proc talk(client: FerusNetworkClient, process: FerusProcess) {.inline.} =
162162
info "network: Created WebSocket connection to address " & $openReq.address &
163163
" successfully!"
164164
client.ipc.send(NetworkWebSocketCreationResult(error: none(string)))
165+
of feGoodbye:
166+
info "network: received goodbye packet."
167+
168+
info "network: closing all websockets"
169+
for ws in client.websockets:
170+
ws.handle.close()
171+
172+
info "network: closing cURL handle"
173+
curl.close()
174+
175+
client.running = false
165176
else:
166177
discard
167178

@@ -170,6 +181,6 @@ proc networkProcessLogic*(client: var IPCClient, process: FerusProcess) {.inline
170181
var client = FerusNetworkClient(ipc: client)
171182
client.ipc.setState(Idling)
172183

173-
while true:
184+
while client.running:
174185
client.talk(process)
175186
client.tickAllConnections()

src/components/network/types.nim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ type
1010
FerusNetworkClient* = ref object
1111
ipc*: IPCClient
1212
websockets*: seq[WebSocketConnection] ## All open WebSocket instances
13+
running*: bool = true

src/components/parsers/html/process.nim

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ proc htmlParse*(oparsingData: Option[ParseHTMLPacket]): HTMLParseResult =
2424

2525
HTMLParseResult(document: some(document.parseHTMLDocument()))
2626

27-
proc talk(client: var IPCClient, process: FerusProcess) {.inline.} =
27+
type HTMLParserData* = object
28+
running*: bool = true
29+
documentsParsed*: uint64
30+
31+
proc talk(
32+
client: var IPCClient, state: var HTMLParserData, process: FerusProcess
33+
) {.inline.} =
2834
var count: cint
2935
discard nix.ioctl(client.socket.getFd().cint, nix.FIONREAD, addr(count))
3036

@@ -53,13 +59,21 @@ proc talk(client: var IPCClient, process: FerusProcess) {.inline.} =
5359

5460
client.send(data)
5561
client.setState(Idling)
62+
63+
inc state.documentsParsed
64+
of feGoodbye:
65+
info "html: got goodbye packet, exiting."
66+
info "html: we parsed " & $state.documentsParsed &
67+
" documents throughout this process's lifetime"
68+
state.running = false
5669
else:
5770
discard
5871

5972
proc htmlParserProcessLogic*(client: var IPCClient, process: FerusProcess) {.inline.} =
6073
info "Entering HTML parser process logic."
74+
var data = HTMLParserData()
6175
client.setState(Idling)
6276
client.poll()
6377

64-
while true:
65-
client.talk(process)
78+
while data.running:
79+
client.talk(data, process)

src/ferus.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ proc main() {.inline.} =
7575
tab1.load()
7676
tabs.add(tab1.move())
7777

78-
while true:
78+
while tabs[0].master.alive:
7979
master.poll()
8080
for i, _ in tabs:
8181
tabs[i].heartbeat()

0 commit comments

Comments
 (0)