-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmaster.odin
More file actions
101 lines (86 loc) · 3.08 KB
/
master.odin
File metadata and controls
101 lines (86 loc) · 3.08 KB
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
package examples
import mbox "../mbox"
import pool_pkg "../pool"
import list "core:container/intrusive/list"
// Master owns a pool and a mailbox together.
// One struct. One shutdown call. No leaks.
Master :: struct {
pool: pool_pkg.Pool(DisposableItm),
inbox: mbox.Mailbox(DisposableItm),
}
// create_master is now a factory proc that demonstrates Idiom 11: errdefer-dispose.
// [itc: errdefer-dispose]
create_master :: proc(initial_msgs: int, max_msgs: int) -> (m: ^Master, ok: bool) {
raw := new(Master) // [itc: heap-master]
// If new fails, we return (nil, false) — ok is false (zero value).
if raw == nil { return }
m_opt: Maybe(^Master) = raw
// named return 'ok' is checked at exit time.
// if post-init setup fails, dispose cleans up the partially-init master.
defer if !ok { master_dispose(&m_opt) }
init_ok, _ := pool_pkg.init(&raw.pool, initial_msgs = initial_msgs, max_msgs = max_msgs,
hooks = DISPOSABLE_ITM_HOOKS)
if !init_ok { return }
// ... potential further setup ...
m = raw
ok = true
return
}
// master_shutdown closes the inbox, returns undelivered items to the pool, then destroys the pool.
//
// Order matters:
// - Return items to pool BEFORE destroy.
// - Calling destroy first would make the returned pointers invalid.
master_shutdown :: proc(m: ^Master) {
remaining, _ := mbox.close(&m.inbox)
for node := list.pop_front(&remaining); node != nil; node = list.pop_front(&remaining) {
itm := container_of(node, DisposableItm, "node")
itm_opt: Maybe(^DisposableItm) = itm
// Demonstrating Idiom 8: dispose-optional
// We could just call disposable_dispose here, but we prefer recycling.
ptr, accepted := pool_pkg.put(&m.pool, &itm_opt) // [itc: dispose-optional]
if !accepted && ptr != nil {
p_opt: Maybe(^DisposableItm) = ptr
disposable_dispose(&p_opt) // [itc: foreign-dispose]
}
}
pool_pkg.destroy(&m.pool)
}
// master_dispose shuts down and frees a heap-allocated Master.
// Follows the ^Maybe(^T) contract: nil inner is a no-op; sets inner to nil on return.
master_dispose :: proc(m: ^Maybe(^Master)) { // [itc: dispose-contract]
mp, ok := m.?
if !ok || mp == nil {return}
master_shutdown(mp)
free(mp)
m^ = nil
}
// master_example shows pool + mailbox owned by one heap-allocated struct.
master_example :: proc() -> bool {
m, ok := create_master(8, 64)
if !ok {
return false
}
m_opt: Maybe(^Master) = m
defer master_dispose(&m_opt) // [itc: defer-dispose]
itm_opt: Maybe(^DisposableItm) // [itc: maybe-container]
// Idiom 4: defer-dispose handles cleanup on send failure
defer disposable_dispose(&itm_opt) // [itc: defer-dispose]
status := pool_pkg.get(&m.pool, &itm_opt)
if status != .Ok || itm_opt == nil {
return false
}
if !mbox.send(&m.inbox, &itm_opt) {
// send failed — return item to pool before defer-dispose fires
// demonstrating Idiom 2: defer-put with Idiom 6: foreign-dispose
defer { // [itc: defer-put]
ptr, accepted := pool_pkg.put(&m.pool, &itm_opt)
if !accepted && ptr != nil {
p_opt: Maybe(^DisposableItm) = ptr
disposable_dispose(&p_opt) // [itc: foreign-dispose]
}
}
return false
}
return true
}