[lxc-devel] [go-lxc/v2] [RFC] Stop using finalizers

caglar10ur on Github lxc-bot at linuxcontainers.org
Wed Dec 26 22:42:46 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 769 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20181226/662fd547/attachment.bin>
-------------- next part --------------
From a6173d2a862b2f9d787028bc72e2ffa561901029 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=2E=C3=87a=C4=9Flar=20Onur?= <caglar at 10ur.org>
Date: Wed, 26 Dec 2018 13:59:19 -0800
Subject: [PATCH 1/2] move examples into individual folders
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: S.Çağlar Onur <caglar at 10ur.org>
---
 .gitignore                                    | 35 ++-----------------
 examples/Makefile                             | 20 +++++------
 examples/{ => attach}/attach.go               |  0
 .../attach_with_pipes.go                      |  0
 examples/{ => checkpoint}/checkpoint.go       |  0
 examples/{ => clone}/clone.go                 |  0
 .../concurrent_create.go                      |  0
 .../concurrent_destroy.go                     |  0
 .../concurrent_shutdown.go                    |  0
 .../concurrent_start.go                       |  0
 .../{ => concurrent_stop}/concurrent_stop.go  |  0
 .../concurrent_stress.go                      |  0
 examples/{ => config}/config.go               |  0
 examples/{ => console}/console.go             |  0
 examples/{ => create}/create.go               |  0
 .../{ => create_snapshot}/create_snapshot.go  |  0
 examples/{ => destroy}/destroy.go             |  0
 .../destroy_snapshots.go                      |  0
 .../device_add_remove.go                      |  0
 examples/{ => execute}/execute.go             |  0
 examples/{ => freeze}/freeze.go               |  0
 examples/{ => interfaces}/interfaces.go       |  0
 examples/{ => ipaddress}/ipaddress.go         |  0
 examples/{ => limit}/limit.go                 |  0
 examples/{ => list}/list.go                   |  0
 examples/{ => list_keys}/list_keys.go         |  0
 .../{ => list_snapshots}/list_snapshots.go    |  0
 examples/{ => reboot}/reboot.go               |  0
 examples/{ => rename}/rename.go               |  0
 .../restore_snapshot.go                       |  0
 examples/{ => shutdown}/shutdown.go           |  0
 examples/{ => start}/start.go                 |  0
 examples/{ => stats}/stats.go                 |  0
 examples/{ => stop}/stop.go                   |  0
 examples/{ => unfreeze}/unfreeze.go           |  0
 35 files changed, 12 insertions(+), 43 deletions(-)
 rename examples/{ => attach}/attach.go (100%)
 rename examples/{ => attach_with_pipes}/attach_with_pipes.go (100%)
 rename examples/{ => checkpoint}/checkpoint.go (100%)
 rename examples/{ => clone}/clone.go (100%)
 rename examples/{ => concurrent_create}/concurrent_create.go (100%)
 rename examples/{ => concurrent_destroy}/concurrent_destroy.go (100%)
 rename examples/{ => concurrent_shutdown}/concurrent_shutdown.go (100%)
 rename examples/{ => concurrent_start}/concurrent_start.go (100%)
 rename examples/{ => concurrent_stop}/concurrent_stop.go (100%)
 rename examples/{ => concurrent_stress}/concurrent_stress.go (100%)
 rename examples/{ => config}/config.go (100%)
 rename examples/{ => console}/console.go (100%)
 rename examples/{ => create}/create.go (100%)
 rename examples/{ => create_snapshot}/create_snapshot.go (100%)
 rename examples/{ => destroy}/destroy.go (100%)
 rename examples/{ => destroy_snapshots}/destroy_snapshots.go (100%)
 rename examples/{ => device_add_remove}/device_add_remove.go (100%)
 rename examples/{ => execute}/execute.go (100%)
 rename examples/{ => freeze}/freeze.go (100%)
 rename examples/{ => interfaces}/interfaces.go (100%)
 rename examples/{ => ipaddress}/ipaddress.go (100%)
 rename examples/{ => limit}/limit.go (100%)
 rename examples/{ => list}/list.go (100%)
 rename examples/{ => list_keys}/list_keys.go (100%)
 rename examples/{ => list_snapshots}/list_snapshots.go (100%)
 rename examples/{ => reboot}/reboot.go (100%)
 rename examples/{ => rename}/rename.go (100%)
 rename examples/{ => restore_snapshot}/restore_snapshot.go (100%)
 rename examples/{ => shutdown}/shutdown.go (100%)
 rename examples/{ => start}/start.go (100%)
 rename examples/{ => stats}/stats.go (100%)
 rename examples/{ => stop}/stop.go (100%)
 rename examples/{ => unfreeze}/unfreeze.go (100%)

diff --git a/.gitignore b/.gitignore
index f1980a2..352fdba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,36 +1,5 @@
-examples/attach
-examples/attach_with_pipes
-examples/checkpoint
-examples/clone
-examples/concurrent_create
-examples/concurrent_destroy
-examples/concurrent_shutdown
-examples/concurrent_start
-examples/concurrent_stop
-examples/concurrent_stress
-examples/config
-examples/console
-examples/create
-examples/create_snapshot
-examples/destroy
-examples/destroy_snapshots
-examples/device_add_remove
-examples/execute
-examples/freeze
-examples/interfaces
-examples/ipaddress
-examples/limit
-examples/list
-examples/list_keys
-examples/list_snapshots
-examples/reboot
-examples/rename
-examples/restore_snapshot
-examples/shutdown
-examples/start
-examples/stats
-examples/stop
-examples/unfreeze
+examples/*/*
+!examples/*/*.go
 coverage.out
 tags
 *.swp
diff --git a/examples/Makefile b/examples/Makefile
index effce0c..8f501e1 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -1,33 +1,33 @@
 NO_COLOR=\033[0m
 OK_COLOR=\033[0;32m
 
-ALL_GO_FILES = $(wildcard *.go)
-ALL_FILES = $(patsubst %.go,%,$(ALL_GO_FILES))
+ALL_GO_FILES = $(wildcard */*.go)
+ALL_BIN_FILES = $(patsubst %.go,%,$(ALL_GO_FILES))
 
-all: $(ALL_FILES)
+all: $(ALL_GO_FILES)
 
 define PROGRAM_template
 $(1): format vet lint
 	@echo "$(OK_COLOR)==> Building $(1) $(NO_COLOR)"
-	@go build $(1).go
+	@cd $(dir $1); go build
 endef
 
-$(foreach prog,$(ALL_FILES),$(eval $(call PROGRAM_template,$(prog))))
+$(foreach prog,$(ALL_GO_FILES),$(eval $(call PROGRAM_template,$(prog))))
 
 clean:
-	@$(foreach file,$(ALL_FILES),rm -f $(file);)
+	@$(foreach file,$(ALL_BIN_FILES),rm -f $(file);)
 
 format:
 	@echo "$(OK_COLOR)==> Formatting the code $(NO_COLOR)"
-	@gofmt -s -w *.go
-	@goimports -w *.go
+	@$(foreach file,$(ALL_GO_FILES),gofmt -s -w $(file);)
+	@$(foreach file,$(ALL_GO_FILES),goimports -w $(file);)
 
 vet:
 	@echo "$(OK_COLOR)==> Running go vet $(NO_COLOR)"
-	@`which go` vet .
+	@$(foreach file,$(ALL_GO_FILES),go vet $(file);)
 
 lint:
 	@echo "$(OK_COLOR)==> Running golint $(NO_COLOR)"
-	@`which golint` .
+	@$(foreach file,$(ALL_GO_FILES),golint $(file);)
 
 .PHONY: all clean format vet lint
diff --git a/examples/attach.go b/examples/attach/attach.go
similarity index 100%
rename from examples/attach.go
rename to examples/attach/attach.go
diff --git a/examples/attach_with_pipes.go b/examples/attach_with_pipes/attach_with_pipes.go
similarity index 100%
rename from examples/attach_with_pipes.go
rename to examples/attach_with_pipes/attach_with_pipes.go
diff --git a/examples/checkpoint.go b/examples/checkpoint/checkpoint.go
similarity index 100%
rename from examples/checkpoint.go
rename to examples/checkpoint/checkpoint.go
diff --git a/examples/clone.go b/examples/clone/clone.go
similarity index 100%
rename from examples/clone.go
rename to examples/clone/clone.go
diff --git a/examples/concurrent_create.go b/examples/concurrent_create/concurrent_create.go
similarity index 100%
rename from examples/concurrent_create.go
rename to examples/concurrent_create/concurrent_create.go
diff --git a/examples/concurrent_destroy.go b/examples/concurrent_destroy/concurrent_destroy.go
similarity index 100%
rename from examples/concurrent_destroy.go
rename to examples/concurrent_destroy/concurrent_destroy.go
diff --git a/examples/concurrent_shutdown.go b/examples/concurrent_shutdown/concurrent_shutdown.go
similarity index 100%
rename from examples/concurrent_shutdown.go
rename to examples/concurrent_shutdown/concurrent_shutdown.go
diff --git a/examples/concurrent_start.go b/examples/concurrent_start/concurrent_start.go
similarity index 100%
rename from examples/concurrent_start.go
rename to examples/concurrent_start/concurrent_start.go
diff --git a/examples/concurrent_stop.go b/examples/concurrent_stop/concurrent_stop.go
similarity index 100%
rename from examples/concurrent_stop.go
rename to examples/concurrent_stop/concurrent_stop.go
diff --git a/examples/concurrent_stress.go b/examples/concurrent_stress/concurrent_stress.go
similarity index 100%
rename from examples/concurrent_stress.go
rename to examples/concurrent_stress/concurrent_stress.go
diff --git a/examples/config.go b/examples/config/config.go
similarity index 100%
rename from examples/config.go
rename to examples/config/config.go
diff --git a/examples/console.go b/examples/console/console.go
similarity index 100%
rename from examples/console.go
rename to examples/console/console.go
diff --git a/examples/create.go b/examples/create/create.go
similarity index 100%
rename from examples/create.go
rename to examples/create/create.go
diff --git a/examples/create_snapshot.go b/examples/create_snapshot/create_snapshot.go
similarity index 100%
rename from examples/create_snapshot.go
rename to examples/create_snapshot/create_snapshot.go
diff --git a/examples/destroy.go b/examples/destroy/destroy.go
similarity index 100%
rename from examples/destroy.go
rename to examples/destroy/destroy.go
diff --git a/examples/destroy_snapshots.go b/examples/destroy_snapshots/destroy_snapshots.go
similarity index 100%
rename from examples/destroy_snapshots.go
rename to examples/destroy_snapshots/destroy_snapshots.go
diff --git a/examples/device_add_remove.go b/examples/device_add_remove/device_add_remove.go
similarity index 100%
rename from examples/device_add_remove.go
rename to examples/device_add_remove/device_add_remove.go
diff --git a/examples/execute.go b/examples/execute/execute.go
similarity index 100%
rename from examples/execute.go
rename to examples/execute/execute.go
diff --git a/examples/freeze.go b/examples/freeze/freeze.go
similarity index 100%
rename from examples/freeze.go
rename to examples/freeze/freeze.go
diff --git a/examples/interfaces.go b/examples/interfaces/interfaces.go
similarity index 100%
rename from examples/interfaces.go
rename to examples/interfaces/interfaces.go
diff --git a/examples/ipaddress.go b/examples/ipaddress/ipaddress.go
similarity index 100%
rename from examples/ipaddress.go
rename to examples/ipaddress/ipaddress.go
diff --git a/examples/limit.go b/examples/limit/limit.go
similarity index 100%
rename from examples/limit.go
rename to examples/limit/limit.go
diff --git a/examples/list.go b/examples/list/list.go
similarity index 100%
rename from examples/list.go
rename to examples/list/list.go
diff --git a/examples/list_keys.go b/examples/list_keys/list_keys.go
similarity index 100%
rename from examples/list_keys.go
rename to examples/list_keys/list_keys.go
diff --git a/examples/list_snapshots.go b/examples/list_snapshots/list_snapshots.go
similarity index 100%
rename from examples/list_snapshots.go
rename to examples/list_snapshots/list_snapshots.go
diff --git a/examples/reboot.go b/examples/reboot/reboot.go
similarity index 100%
rename from examples/reboot.go
rename to examples/reboot/reboot.go
diff --git a/examples/rename.go b/examples/rename/rename.go
similarity index 100%
rename from examples/rename.go
rename to examples/rename/rename.go
diff --git a/examples/restore_snapshot.go b/examples/restore_snapshot/restore_snapshot.go
similarity index 100%
rename from examples/restore_snapshot.go
rename to examples/restore_snapshot/restore_snapshot.go
diff --git a/examples/shutdown.go b/examples/shutdown/shutdown.go
similarity index 100%
rename from examples/shutdown.go
rename to examples/shutdown/shutdown.go
diff --git a/examples/start.go b/examples/start/start.go
similarity index 100%
rename from examples/start.go
rename to examples/start/start.go
diff --git a/examples/stats.go b/examples/stats/stats.go
similarity index 100%
rename from examples/stats.go
rename to examples/stats/stats.go
diff --git a/examples/stop.go b/examples/stop/stop.go
similarity index 100%
rename from examples/stop.go
rename to examples/stop/stop.go
diff --git a/examples/unfreeze.go b/examples/unfreeze/unfreeze.go
similarity index 100%
rename from examples/unfreeze.go
rename to examples/unfreeze/unfreeze.go

From 372cc9cdebf64c372602ff7b2d5d15dfb3a6f388 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=2E=C3=87a=C4=9Flar=20Onur?= <caglar at 10ur.org>
Date: Wed, 26 Dec 2018 14:24:33 -0800
Subject: [PATCH 2/2] Stop using finalizers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Handling our garbage explicitly is way more simpler and idiomatic
then relying on runtime magic. Finalizers also are not guaranteed to
run so stop using them, instead Container now provides Release()
to call it via defer.

Signed-off-by: S.Çağlar Onur <caglar at 10ur.org>
---
 container.go                                   | 12 ++++++++++++
 error.go                                       |  1 +
 examples/attach/attach.go                      |  1 +
 .../attach_with_pipes/attach_with_pipes.go     |  1 +
 examples/checkpoint/checkpoint.go              |  1 +
 examples/clone/clone.go                        |  1 +
 .../concurrent_create/concurrent_create.go     |  1 +
 .../concurrent_destroy/concurrent_destroy.go   |  1 +
 .../concurrent_shutdown/concurrent_shutdown.go |  1 +
 examples/concurrent_start/concurrent_start.go  |  1 +
 examples/concurrent_stop/concurrent_stop.go    |  1 +
 .../concurrent_stress/concurrent_stress.go     |  1 +
 examples/config/config.go                      |  2 +-
 examples/console/console.go                    |  1 +
 examples/create/create.go                      |  1 +
 examples/create_snapshot/create_snapshot.go    |  1 +
 examples/destroy/destroy.go                    |  1 +
 .../destroy_snapshots/destroy_snapshots.go     |  1 +
 .../device_add_remove/device_add_remove.go     |  1 +
 examples/execute/execute.go                    |  1 +
 examples/freeze/freeze.go                      |  1 +
 examples/interfaces/interfaces.go              |  1 +
 examples/ipaddress/ipaddress.go                |  1 +
 examples/limit/limit.go                        |  1 +
 examples/list/list.go                          |  3 +++
 examples/list_keys/list_keys.go                |  1 +
 examples/list_snapshots/list_snapshots.go      |  1 +
 examples/reboot/reboot.go                      |  1 +
 examples/rename/rename.go                      |  1 +
 examples/restore_snapshot/restore_snapshot.go  |  1 +
 examples/shutdown/shutdown.go                  |  1 +
 examples/start/start.go                        |  1 +
 examples/stats/stats.go                        |  1 +
 examples/stop/stop.go                          |  1 +
 examples/unfreeze/unfreeze.go                  |  1 +
 lxc-binding.go                                 | 18 ++++++++----------
 36 files changed, 56 insertions(+), 11 deletions(-)

diff --git a/container.go b/container.go
index cd46b38..22e9c71 100644
--- a/container.go
+++ b/container.go
@@ -101,6 +101,18 @@ func (c *Container) setCgroupItemWithByteSize(filename string, limit ByteSize, m
 	return nil
 }
 
+// Release decrements the reference counter of the container object.
+// nil on success or if reference was successfully dropped and container has been freed, and ErrReleaseFailed on error.
+func (c *Container) Release() error {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	if C.lxc_container_put(c.container) == -1 {
+		return ErrReleaseFailed
+	}
+	return nil
+}
+
 func (c *Container) name() string {
 	return C.GoString(c.container.name)
 }
diff --git a/error.go b/error.go
index b89d903..e426935 100644
--- a/error.go
+++ b/error.go
@@ -67,6 +67,7 @@ var (
 	ErrTemplateNotAllowed            = NewError("unprivileged users only allowed to use \"download\" template")
 	ErrUnfreezeFailed                = NewError("unfreezing the container failed")
 	ErrUnknownBackendStore           = NewError("unknown backend type")
+	ErrReleaseFailed                 = NewError("releasing the container failed")
 )
 
 // Error represents a basic error that implies the error interface.
diff --git a/examples/attach/attach.go b/examples/attach/attach.go
index b8b4b48..528936c 100644
--- a/examples/attach/attach.go
+++ b/examples/attach/attach.go
@@ -35,6 +35,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	options := lxc.DefaultAttachOptions
 	options.ClearEnv = false
diff --git a/examples/attach_with_pipes/attach_with_pipes.go b/examples/attach_with_pipes/attach_with_pipes.go
index ece8aaa..e1c6156 100644
--- a/examples/attach_with_pipes/attach_with_pipes.go
+++ b/examples/attach_with_pipes/attach_with_pipes.go
@@ -39,6 +39,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	stdoutReader, stdoutWriter, err := os.Pipe()
 	if err != nil {
diff --git a/examples/checkpoint/checkpoint.go b/examples/checkpoint/checkpoint.go
index a3a5a85..6a1fee8 100644
--- a/examples/checkpoint/checkpoint.go
+++ b/examples/checkpoint/checkpoint.go
@@ -35,6 +35,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	if verbose {
 		c.SetVerbosity(lxc.Verbose)
diff --git a/examples/clone/clone.go b/examples/clone/clone.go
index bc95b7c..1be4f3b 100644
--- a/examples/clone/clone.go
+++ b/examples/clone/clone.go
@@ -31,6 +31,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	if backend == 0 {
 		log.Fatalf("ERROR: %s\n", lxc.ErrUnknownBackendStore)
diff --git a/examples/concurrent_create/concurrent_create.go b/examples/concurrent_create/concurrent_create.go
index 5dafc62..8ac5897 100644
--- a/examples/concurrent_create/concurrent_create.go
+++ b/examples/concurrent_create/concurrent_create.go
@@ -39,6 +39,7 @@ func main() {
 			if err != nil {
 				log.Fatalf("ERROR: %s\n", err.Error())
 			}
+			defer c.Release()
 
 			log.Printf("Creating the container (%d)...\n", i)
 			if err := c.Create(options); err != nil {
diff --git a/examples/concurrent_destroy/concurrent_destroy.go b/examples/concurrent_destroy/concurrent_destroy.go
index 7ea678d..04e06af 100644
--- a/examples/concurrent_destroy/concurrent_destroy.go
+++ b/examples/concurrent_destroy/concurrent_destroy.go
@@ -38,6 +38,7 @@ func main() {
 			if err != nil {
 				log.Fatalf("ERROR: %s\n", err.Error())
 			}
+			defer c.Release()
 
 			log.Printf("Destroying the container (%d)...\n", i)
 			if err := c.Destroy(); err != nil {
diff --git a/examples/concurrent_shutdown/concurrent_shutdown.go b/examples/concurrent_shutdown/concurrent_shutdown.go
index adcdadf..a795f2f 100644
--- a/examples/concurrent_shutdown/concurrent_shutdown.go
+++ b/examples/concurrent_shutdown/concurrent_shutdown.go
@@ -39,6 +39,7 @@ func main() {
 			if err != nil {
 				log.Fatalf("ERROR: %s\n", err.Error())
 			}
+			defer c.Release()
 
 			log.Printf("Shutting down the container (%d)...\n", i)
 			if err := c.Shutdown(30 * time.Second); err != nil {
diff --git a/examples/concurrent_start/concurrent_start.go b/examples/concurrent_start/concurrent_start.go
index 3d01656..6cfc7af 100644
--- a/examples/concurrent_start/concurrent_start.go
+++ b/examples/concurrent_start/concurrent_start.go
@@ -38,6 +38,7 @@ func main() {
 			if err != nil {
 				log.Fatalf("ERROR: %s\n", err.Error())
 			}
+			defer c.Release()
 
 			log.Printf("Starting the container (%d)...\n", i)
 			if err := c.Start(); err != nil {
diff --git a/examples/concurrent_stop/concurrent_stop.go b/examples/concurrent_stop/concurrent_stop.go
index 57fc2c1..d5f506a 100644
--- a/examples/concurrent_stop/concurrent_stop.go
+++ b/examples/concurrent_stop/concurrent_stop.go
@@ -38,6 +38,7 @@ func main() {
 			if err != nil {
 				log.Fatalf("ERROR: %s\n", err.Error())
 			}
+			defer c.Release()
 
 			log.Printf("Stoping the container (%d)...\n", i)
 			if err := c.Stop(); err != nil {
diff --git a/examples/concurrent_stress/concurrent_stress.go b/examples/concurrent_stress/concurrent_stress.go
index f9026a9..b68deaa 100644
--- a/examples/concurrent_stress/concurrent_stress.go
+++ b/examples/concurrent_stress/concurrent_stress.go
@@ -62,6 +62,7 @@ func main() {
 					if err != nil {
 						log.Fatalf("ERROR: %s\n", err.Error())
 					}
+					defer c.Release()
 
 					if mode == "CREATE" && startstop == false {
 						log.Printf("\t\tCreating the container (%d)...\n", i)
diff --git a/examples/config/config.go b/examples/config/config.go
index 439539c..b5a8fbd 100644
--- a/examples/config/config.go
+++ b/examples/config/config.go
@@ -27,11 +27,11 @@ func init() {
 }
 
 func main() {
-
 	c, err := lxc.NewContainer(name, lxcpath)
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	//setting hostname
 	err = c.SetConfigItem("lxc.utsname", hostname)
diff --git a/examples/console/console.go b/examples/console/console.go
index 651f9ff..b26efa1 100644
--- a/examples/console/console.go
+++ b/examples/console/console.go
@@ -29,6 +29,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	log.Printf("Attaching to container's console...\n")
 	if err := c.Console(lxc.DefaultConsoleOptions); err != nil {
diff --git a/examples/create/create.go b/examples/create/create.go
index 1714bb3..1e71d25 100644
--- a/examples/create/create.go
+++ b/examples/create/create.go
@@ -43,6 +43,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	log.Printf("Creating container...\n")
 	if verbose {
diff --git a/examples/create_snapshot/create_snapshot.go b/examples/create_snapshot/create_snapshot.go
index d86cd1b..b31d2fa 100644
--- a/examples/create_snapshot/create_snapshot.go
+++ b/examples/create_snapshot/create_snapshot.go
@@ -29,6 +29,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	log.Printf("Snapshoting the container...\n")
 	if _, err := c.CreateSnapshot(); err != nil {
diff --git a/examples/destroy/destroy.go b/examples/destroy/destroy.go
index c294385..81767dc 100644
--- a/examples/destroy/destroy.go
+++ b/examples/destroy/destroy.go
@@ -29,6 +29,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	log.Printf("Destroying container...\n")
 	if err := c.Destroy(); err != nil {
diff --git a/examples/destroy_snapshots/destroy_snapshots.go b/examples/destroy_snapshots/destroy_snapshots.go
index 07d1b14..5210f3e 100644
--- a/examples/destroy_snapshots/destroy_snapshots.go
+++ b/examples/destroy_snapshots/destroy_snapshots.go
@@ -27,5 +27,6 @@ func main() {
 				log.Fatalf("ERROR: %s\n", err.Error())
 			}
 		}
+		c[i].Release()
 	}
 }
diff --git a/examples/device_add_remove/device_add_remove.go b/examples/device_add_remove/device_add_remove.go
index 56b9c83..da6783f 100644
--- a/examples/device_add_remove/device_add_remove.go
+++ b/examples/device_add_remove/device_add_remove.go
@@ -30,6 +30,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	if err := c.AddDeviceNode("/dev/network_latency"); err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
diff --git a/examples/execute/execute.go b/examples/execute/execute.go
index a5cb350..fc5af47 100644
--- a/examples/execute/execute.go
+++ b/examples/execute/execute.go
@@ -29,6 +29,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	c.LoadConfigFile(lxc.DefaultConfigPath())
 	if output, err := c.Execute("uname", "-a"); err != nil {
diff --git a/examples/freeze/freeze.go b/examples/freeze/freeze.go
index c13a123..7f063c5 100644
--- a/examples/freeze/freeze.go
+++ b/examples/freeze/freeze.go
@@ -30,6 +30,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	log.Printf("Freezing the container...\n")
 	if err := c.Freeze(); err != nil {
diff --git a/examples/interfaces/interfaces.go b/examples/interfaces/interfaces.go
index eea8580..c61beff 100644
--- a/examples/interfaces/interfaces.go
+++ b/examples/interfaces/interfaces.go
@@ -29,6 +29,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	log.Printf("Interfaces\n")
 	if interfaces, err := c.Interfaces(); err != nil {
diff --git a/examples/ipaddress/ipaddress.go b/examples/ipaddress/ipaddress.go
index f52fd77..e4a878b 100644
--- a/examples/ipaddress/ipaddress.go
+++ b/examples/ipaddress/ipaddress.go
@@ -29,6 +29,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	log.Printf("IPAddress(\"lo\")\n")
 	if addresses, err := c.IPAddress("lo"); err != nil {
diff --git a/examples/limit/limit.go b/examples/limit/limit.go
index 2d2a38b..dd5c453 100644
--- a/examples/limit/limit.go
+++ b/examples/limit/limit.go
@@ -29,6 +29,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	memLimit, err := c.MemoryLimit()
 	if err != nil {
diff --git a/examples/list/list.go b/examples/list/list.go
index 8434225..0f17030 100644
--- a/examples/list/list.go
+++ b/examples/list/list.go
@@ -27,6 +27,7 @@ func main() {
 	c := lxc.DefinedContainers(lxcpath)
 	for i := range c {
 		log.Printf("%s (%s)\n", c[i].Name(), c[i].State())
+		c[i].Release()
 	}
 
 	log.Println()
@@ -35,6 +36,7 @@ func main() {
 	c = lxc.ActiveContainers(lxcpath)
 	for i := range c {
 		log.Printf("%s (%s)\n", c[i].Name(), c[i].State())
+		c[i].Release()
 	}
 
 	log.Println()
@@ -43,5 +45,6 @@ func main() {
 	c = lxc.ActiveContainers(lxcpath)
 	for i := range c {
 		log.Printf("%s (%s)\n", c[i].Name(), c[i].State())
+		c[i].Release()
 	}
 }
diff --git a/examples/list_keys/list_keys.go b/examples/list_keys/list_keys.go
index 18bbaa0..90d37d4 100644
--- a/examples/list_keys/list_keys.go
+++ b/examples/list_keys/list_keys.go
@@ -29,6 +29,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	for _, k := range c.ConfigKeys() {
 		log.Printf("%s -> %s", k, c.ConfigItem(k))
diff --git a/examples/list_snapshots/list_snapshots.go b/examples/list_snapshots/list_snapshots.go
index 640dff5..8ed2359 100644
--- a/examples/list_snapshots/list_snapshots.go
+++ b/examples/list_snapshots/list_snapshots.go
@@ -28,5 +28,6 @@ func main() {
 			log.Printf("LXC path: %s\n", s.Path)
 			log.Println()
 		}
+		c[i].Release()
 	}
 }
diff --git a/examples/reboot/reboot.go b/examples/reboot/reboot.go
index 78133d0..db4c5ad 100644
--- a/examples/reboot/reboot.go
+++ b/examples/reboot/reboot.go
@@ -29,6 +29,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	log.Printf("Rebooting the container...\n")
 	if err := c.Reboot(); err != nil {
diff --git a/examples/rename/rename.go b/examples/rename/rename.go
index 4c4a4b3..8212dcf 100644
--- a/examples/rename/rename.go
+++ b/examples/rename/rename.go
@@ -31,6 +31,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	log.Printf("Renaming container to %s...\n", newname)
 	if err := c.Rename(newname); err != nil {
diff --git a/examples/restore_snapshot/restore_snapshot.go b/examples/restore_snapshot/restore_snapshot.go
index feb5cc6..3be2972 100644
--- a/examples/restore_snapshot/restore_snapshot.go
+++ b/examples/restore_snapshot/restore_snapshot.go
@@ -29,6 +29,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	log.Printf("Restoring the container...\n")
 	snapshot := lxc.Snapshot{Name: "snap0"}
diff --git a/examples/shutdown/shutdown.go b/examples/shutdown/shutdown.go
index b361aaf..5ef712c 100644
--- a/examples/shutdown/shutdown.go
+++ b/examples/shutdown/shutdown.go
@@ -30,6 +30,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	log.Printf("Shutting down the container...\n")
 	if err := c.Shutdown(30 * time.Second); err != nil {
diff --git a/examples/start/start.go b/examples/start/start.go
index 7005c17..4e26f1f 100644
--- a/examples/start/start.go
+++ b/examples/start/start.go
@@ -30,6 +30,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	c.SetLogFile("/tmp/" + name + ".log")
 	c.SetLogLevel(lxc.TRACE)
diff --git a/examples/stats/stats.go b/examples/stats/stats.go
index b1ee53f..7a3bd6f 100644
--- a/examples/stats/stats.go
+++ b/examples/stats/stats.go
@@ -29,6 +29,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	// mem
 	memUsed, err := c.MemoryUsage()
diff --git a/examples/stop/stop.go b/examples/stop/stop.go
index 2ec77c8..f95ff53 100644
--- a/examples/stop/stop.go
+++ b/examples/stop/stop.go
@@ -29,6 +29,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	c.SetLogFile("/tmp/" + name + ".log")
 	c.SetLogLevel(lxc.TRACE)
diff --git a/examples/unfreeze/unfreeze.go b/examples/unfreeze/unfreeze.go
index 1f4d08e..bf7905f 100644
--- a/examples/unfreeze/unfreeze.go
+++ b/examples/unfreeze/unfreeze.go
@@ -30,6 +30,7 @@ func main() {
 	if err != nil {
 		log.Fatalf("ERROR: %s\n", err.Error())
 	}
+	defer c.Release()
 
 	log.Printf("Unfreezing the container...\n")
 	if err := c.Unfreeze(); err != nil {
diff --git a/lxc-binding.go b/lxc-binding.go
index 3cd38d6..a0e2bdc 100644
--- a/lxc-binding.go
+++ b/lxc-binding.go
@@ -18,13 +18,13 @@ import "C"
 
 import (
 	"fmt"
-	"runtime"
 	"strconv"
 	"strings"
 	"unsafe"
 )
 
 // NewContainer returns a new container struct.
+// Caller needs to call Release() on the returned container to release its resources.
 func NewContainer(name string, lxcpath ...string) (*Container, error) {
 	var container *C.struct_lxc_container
 
@@ -45,8 +45,6 @@ func NewContainer(name string, lxcpath ...string) (*Container, error) {
 	}
 	c := &Container{container: container, verbosity: Quiet}
 
-	// http://golang.org/pkg/runtime/#SetFinalizer
-	runtime.SetFinalizer(c, Release)
 	return c, nil
 }
 
@@ -57,13 +55,10 @@ func Acquire(c *Container) bool {
 
 // Release decrements the reference counter of the container object.
 func Release(c *Container) bool {
-	// http://golang.org/pkg/runtime/#SetFinalizer
-	runtime.SetFinalizer(c, nil)
-
-	// Go is bad at refcounting sometimes
-	c.mu.Lock()
-
-	return C.lxc_container_put(c.container) == 1
+	if C.lxc_container_put(c.container) == -1 {
+		return false
+	}
+	return true
 }
 
 // Version returns the LXC version.
@@ -124,6 +119,7 @@ func ContainerNames(lxcpath ...string) []string {
 
 // Containers returns the defined and active containers on the system. Only
 // containers that could retrieved successfully are returned.
+// Caller needs to call Release() on the returned containers to release resources.
 func Containers(lxcpath ...string) []*Container {
 	var containers []*Container
 
@@ -159,6 +155,7 @@ func DefinedContainerNames(lxcpath ...string) []string {
 
 // DefinedContainers returns the defined containers on the system.  Only
 // containers that could retrieved successfully are returned.
+// Caller needs to call Release() on the returned containers to release resources.
 func DefinedContainers(lxcpath ...string) []*Container {
 	var containers []*Container
 
@@ -194,6 +191,7 @@ func ActiveContainerNames(lxcpath ...string) []string {
 
 // ActiveContainers returns the active containers on the system. Only
 // containers that could retrieved successfully are returned.
+// Caller needs to call Release() on the returned containers to release resources.
 func ActiveContainers(lxcpath ...string) []*Container {
 	var containers []*Container
 


More information about the lxc-devel mailing list