Skip to content

Commit 7a81740

Browse files
committed
Merge pull request #64 from bcwaldon/two-conns-one-dbus
Use separate connection for dbus signals
2 parents 0d52c1e + afaa487 commit 7a81740

File tree

3 files changed

+72
-60
lines changed

3 files changed

+72
-60
lines changed

dbus/dbus.go

Lines changed: 49 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,14 @@ func PathBusEscape(path string) string {
6464

6565
// Conn is a connection to systemd's dbus endpoint.
6666
type Conn struct {
67-
sysconn *dbus.Conn
68-
sysobj *dbus.Object
67+
// sysconn/sysobj are only used to call dbus methods
68+
sysconn *dbus.Conn
69+
sysobj *dbus.Object
70+
71+
// sigconn/sigobj are only used to receive dbus signals
72+
sigconn *dbus.Conn
73+
sigobj *dbus.Object
74+
6975
jobListener struct {
7076
jobs map[dbus.ObjectPath]chan string
7177
sync.Mutex
@@ -77,65 +83,74 @@ type Conn struct {
7783
ignore map[dbus.ObjectPath]int64
7884
cleanIgnore int64
7985
}
80-
dispatch map[string]func(dbus.Signal)
8186
}
8287

83-
// New() establishes a connection to the system bus and authenticates.
88+
// New establishes a connection to the system bus and authenticates.
8489
func New() (*Conn, error) {
85-
c := new(Conn)
86-
87-
if err := c.initConnection(dbus.SystemBusPrivate); err != nil {
88-
return nil, err
89-
}
90-
91-
c.initJobs()
92-
return c, nil
90+
return newConnection(dbus.SystemBusPrivate)
9391
}
9492

95-
// NewUserConnection() establishes a connection to the session bus and
93+
// NewUserConnection establishes a connection to the session bus and
9694
// authenticates. This can be used to connect to systemd user instances.
9795
func NewUserConnection() (*Conn, error) {
98-
c := new(Conn)
96+
return newConnection(dbus.SessionBusPrivate)
97+
}
98+
99+
func newConnection(createBus func() (*dbus.Conn, error)) (*Conn, error) {
100+
sysconn, err := dbusConnection(createBus)
101+
if err != nil {
102+
return nil, err
103+
}
99104

100-
if err := c.initConnection(dbus.SessionBusPrivate); err != nil {
105+
sigconn, err := dbusConnection(createBus)
106+
if err != nil {
101107
return nil, err
102108
}
103109

104-
c.initJobs()
110+
c := &Conn{
111+
sysconn: sysconn,
112+
sysobj: systemdObject(sysconn),
113+
sigconn: sigconn,
114+
sigobj: systemdObject(sigconn),
115+
}
116+
117+
c.subscriber.ignore = make(map[dbus.ObjectPath]int64)
118+
c.jobListener.jobs = make(map[dbus.ObjectPath]chan string)
119+
120+
// Setup the listeners on jobs so that we can get completions
121+
c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
122+
"type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'")
123+
124+
c.dispatch()
105125
return c, nil
106126
}
107127

108-
func (c *Conn) initConnection(createBus func()(*dbus.Conn, error)) error {
109-
var err error
110-
c.sysconn, err = createBus()
128+
func dbusConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) {
129+
conn, err := createBus()
111130
if err != nil {
112-
return err
131+
return nil, err
113132
}
114133

115134
// Only use EXTERNAL method, and hardcode the uid (not username)
116135
// to avoid a username lookup (which requires a dynamically linked
117136
// libc)
118137
methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))}
119138

120-
err = c.sysconn.Auth(methods)
139+
err = conn.Auth(methods)
121140
if err != nil {
122-
c.sysconn.Close()
123-
return err
141+
conn.Close()
142+
return nil, err
124143
}
125144

126-
err = c.sysconn.Hello()
145+
err = conn.Hello()
127146
if err != nil {
128-
c.sysconn.Close()
129-
return err
147+
conn.Close()
148+
return nil, err
130149
}
131150

132-
c.sysobj = c.sysconn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1"))
133-
134-
// Setup the listeners on jobs so that we can get completions
135-
c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
136-
"type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'")
137-
c.initSubscription()
138-
c.initDispatch()
151+
return conn, nil
152+
}
139153

140-
return nil
154+
func systemdObject(conn *dbus.Conn) *dbus.Object {
155+
return conn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1"))
141156
}

dbus/methods.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@ import (
2222
"github.com/godbus/dbus"
2323
)
2424

25-
func (c *Conn) initJobs() {
26-
c.jobListener.jobs = make(map[dbus.ObjectPath]chan string)
27-
}
28-
2925
func (c *Conn) jobComplete(signal *dbus.Signal) {
3026
var id uint32
3127
var job dbus.ObjectPath

dbus/subscription.go

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ const (
3333
// systemd will automatically stop sending signals so there is no need to
3434
// explicitly call Unsubscribe().
3535
func (c *Conn) Subscribe() error {
36-
c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
36+
c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
3737
"type='signal',interface='org.freedesktop.systemd1.Manager',member='UnitNew'")
38-
c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
38+
c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
3939
"type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'")
4040

41-
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store()
41+
err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store()
4242
if err != nil {
4343
return err
4444
}
@@ -48,22 +48,18 @@ func (c *Conn) Subscribe() error {
4848

4949
// Unsubscribe this connection from systemd dbus events.
5050
func (c *Conn) Unsubscribe() error {
51-
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store()
51+
err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store()
5252
if err != nil {
5353
return err
5454
}
5555

5656
return nil
5757
}
5858

59-
func (c *Conn) initSubscription() {
60-
c.subscriber.ignore = make(map[dbus.ObjectPath]int64)
61-
}
62-
63-
func (c *Conn) initDispatch() {
59+
func (c *Conn) dispatch() {
6460
ch := make(chan *dbus.Signal, signalBuffer)
6561

66-
c.sysconn.Signal(ch)
62+
c.sigconn.Signal(ch)
6763

6864
go func() {
6965
for {
@@ -72,24 +68,32 @@ func (c *Conn) initDispatch() {
7268
return
7369
}
7470

75-
switch signal.Name {
76-
case "org.freedesktop.systemd1.Manager.JobRemoved":
71+
if signal.Name == "org.freedesktop.systemd1.Manager.JobRemoved" {
7772
c.jobComplete(signal)
73+
}
74+
75+
if c.subscriber.updateCh == nil {
76+
continue
77+
}
7878

79+
var unitPath dbus.ObjectPath
80+
switch signal.Name {
81+
case "org.freedesktop.systemd1.Manager.JobRemoved":
7982
unitName := signal.Body[2].(string)
80-
var unitPath dbus.ObjectPath
8183
c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath)
82-
if unitPath != dbus.ObjectPath("") {
83-
c.sendSubStateUpdate(unitPath)
84-
}
8584
case "org.freedesktop.systemd1.Manager.UnitNew":
86-
c.sendSubStateUpdate(signal.Body[1].(dbus.ObjectPath))
85+
unitPath = signal.Body[1].(dbus.ObjectPath)
8786
case "org.freedesktop.DBus.Properties.PropertiesChanged":
8887
if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" {
89-
// we only care about SubState updates, which are a Unit property
90-
c.sendSubStateUpdate(signal.Path)
88+
unitPath = signal.Path
9189
}
9290
}
91+
92+
if unitPath == dbus.ObjectPath("") {
93+
continue
94+
}
95+
96+
c.sendSubStateUpdate(unitPath)
9397
}
9498
}()
9599
}
@@ -176,9 +180,6 @@ func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan
176180
func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) {
177181
c.subscriber.Lock()
178182
defer c.subscriber.Unlock()
179-
if c.subscriber.updateCh == nil {
180-
return
181-
}
182183

183184
if c.shouldIgnore(path) {
184185
return

0 commit comments

Comments
 (0)