blob: 8f9103587dba8dfb261cc08c771503886cae9f51 (
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
|
package gui
// A Killable object can be told to shut down by sending a signal via the Kill() channel.
// As its last action, the object posts a signal to Dead() and closes both channels, indicating that it has finished shutting down.
type Killable interface {
Kill() chan<- bool
Dead() <-chan bool
}
// A killer can kill the object that is attached to it.
// The victim can attach itself to the killer by sending an attachMsg via the provided attach() channel.
// The attachMsg contains the victim itself and a `detach' channel.
// The victim can detatch itself from the killer by signalling over the `detach' channel.
//
// Only one victim can be attached to the killer at a time.
// Further messages sent on the attach() channel will block until the current victim is detached.
type killer interface {
attach() chan<- attachMsg
}
// attachMsg is sent to a killer to attach the victim.
type attachMsg struct {
victim Killable
detach <-chan bool
}
// attachHandler implements killer. It allows victims to attach themselves via the attach channel.
// There can only be one attached victim at a time.
// If attachHandler is killed while a victim is attached, it kills the victim.
// When killed, the victim must detach itself before dying.
type attachHandler struct {
attach chan<- attachMsg
kill chan<- bool
dead <-chan bool
}
func newAttachHandler() attachHandler {
attach := make(chan attachMsg)
kill := make(chan bool)
dead := make(chan bool)
go func() {
defer func() {
dead <- true
close(dead)
}()
defer close(kill)
defer close(attach)
for {
var attached attachMsg
select {
case attached = <-attach:
case <-kill:
return
}
Attached:
for {
select {
case <-attached.detach:
break Attached
case <-kill:
attached.victim.Kill() <- true
<-attached.detach
<-attached.victim.Dead()
return
}
}
}
}()
return attachHandler{attach, kill, dead}
}
|