On Thu, Dec 29, 2016 at 1:45 PM, George Dunlap <george.dun...@citrix.com> wrote:
> At a high level: I think I began by saying that this would probably all
> be a single patch.  But I think it would probably be easier to review
> the different decisions made at each point by filling out the file bit
> by bit, and explaining what's going on at each point.

[snip]

> I'll take a stab at breaking it down in an example order that makes some
> sense to me, and then you can see what you think.

Here's one way you might break down this series that would make it
easier to review.

I've re-ordered the file somewhat, and there's a slight bug in the
build process so I can't compile it; and many of the descriptions need
to be expanded.  But it should give you the idea of what I'm talking
about.

 -George
From c96a7c71c69c440fd87e77b5e11f7ecdf3263e83 Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dun...@citrix.com>
Date: Thu, 29 Dec 2016 19:22:41 +0000
Subject: [PATCH 1/7] tools/xenlight: Create stub package

Create a basic Makefile to build and install libxenlight Golang
bindings.  Also add a stub package which only opens libxl context.

Include a global xenlight.Ctx variable which can be used as the
default context by the entire program if desired.

For now, return simple errors.  Proper error handling will be added in
the next patch.

Signed-off-by: Ronald Rojas <ronlad...@gmail.com>
---
 tools/Makefile                    | 16 ++++++++
 tools/golang/Makefile             | 29 ++++++++++++++
 tools/golang/xenlight/xenlight.go | 80 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 125 insertions(+)
 create mode 100644 tools/golang/Makefile
 create mode 100644 tools/golang/xenlight/xenlight.go

diff --git a/tools/Makefile b/tools/Makefile
index 77e0723..4c34421 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -12,6 +12,8 @@ SUBDIRS-y += misc
 SUBDIRS-y += examples
 SUBDIRS-y += hotplug
 SUBDIRS-y += xentrace
+SUBDIRS-y += golang
+#FIXME: Have golang controlled by a configure variable
 SUBDIRS-$(CONFIG_XCUTILS) += xcutils
 SUBDIRS-$(CONFIG_X86) += firmware
 SUBDIRS-y += console
@@ -312,6 +314,20 @@ subdir-install-debugger/gdbsx: .phony
 subdir-all-debugger/gdbsx: .phony
        $(MAKE) -C debugger/gdbsx all
 
+subdir-all-golang/xenlight: .phony
+       $(MAKE) -C golang all
+
+subdir-clean-golang/xenlight: .phony
+       $(MAKE) -C golang clean
+
+subdir-install-golang/xenlight: .phony
+       $(MAKE) -C golang install
+
+subdir-build-golang/xenlight: .phony
+       $(MAKE) -C golang build
+
+subdir-distclean-golang/xenlight: .phony
+       $(MAKE) -C golang distclean
 
 subdir-clean-debugger/kdd subdir-distclean-debugger/kdd: .phony
        $(MAKE) -C debugger/kdd clean
diff --git a/tools/golang/Makefile b/tools/golang/Makefile
new file mode 100644
index 0000000..96589c8
--- /dev/null
+++ b/tools/golang/Makefile
@@ -0,0 +1,29 @@
+XEN_ROOT=$(CURDIR)/../..
+GOLANG_SRC=$(GOPATH)/src/xenproject.org/xenlight
+include $(XEN_ROOT)/tools/Rules.mk
+
+BINARY = xenlight.a
+GO ?= go
+
+.PHONY: all
+all: build
+
+.PHONY: build
+build: xenlight/xenlight.a
+
+.PHONY: install
+install: build
+       $(INSTALL_DIR) $(DESTDIR)$(GOLANG_SRC)
+       $(INSTALL_DATA) xenlight/xenlight.go $(DESTDIR)$(GOLANG_SRC)
+
+.PHONY: clean
+clean:
+       $(RM) xenlight/$(BINARY)
+
+.PHONY: distclean
+distclean: clean
+
+xenlight/xenlight.a: xenlight/xenlight.go
+       $(GO) build -o $@ $<
+
+-include $(DEPS)
diff --git a/tools/golang/xenlight/xenlight.go 
b/tools/golang/xenlight/xenlight.go
new file mode 100644
index 0000000..b162abb
--- /dev/null
+++ b/tools/golang/xenlight/xenlight.go
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 George W. Dunlap, Citrix Systems UK Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License only.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+package xenlight
+
+/*
+#cgo LDFLAGS: -lxenlight -lyajl
+#include <stdlib.h>
+#include <libxl.h>
+*/
+import "C"
+
+import (
+       "fmt"
+       "time"
+       "unsafe"
+)
+
+/*
+ * Types: Builtins
+ */
+type Context struct {
+       ctx *C.libxl_ctx
+}
+
+/*
+ * Context
+ */
+var Ctx Context
+
+func (Ctx *Context) IsOpen() bool {
+       return Ctx.ctx != nil
+}
+
+func (Ctx *Context) Open() (err error) {
+       if Ctx.ctx != nil {
+               return
+       }
+
+       ret := C.libxl_ctx_alloc(unsafe.Pointer(&Ctx.ctx), C.LIBXL_VERSION, 0, 
nil)
+
+       if ret != 0 {
+               //FIXME: proper error
+               err = createError("Allocating libxl context: ", ret)
+       }
+       return
+}
+
+func (Ctx *Context) Close() (err error) {
+       ret := C.libxl_ctx_free(unsafe.Pointer(Ctx.ctx))
+       Ctx.ctx = nil
+
+       if ret != 0 {
+               //FIXME: proper error
+               err = createError("Freeing libxl context: ", ret)
+       }
+       return
+}
+
+func (Ctx *Context) CheckOpen() (err error) {
+       if Ctx.ctx == nil {
+               err = fmt.Errorf("Context not opened")
+       }
+       return
+}
-- 
2.1.4

From b57339b6f42dd1997d8aef3580dfb7411a56a99f Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dun...@citrix.com>
Date: Thu, 29 Dec 2016 19:36:15 +0000
Subject: [PATCH 2/7] tools/golang: Add error constants and standard handling

You're going to change this so I won't bother writing a description -- write
here though a description of what the patch does and a brief account of why.
---
 tools/golang/xenlight/xenlight.go | 90 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/tools/golang/xenlight/xenlight.go 
b/tools/golang/xenlight/xenlight.go
index b162abb..677e5a5 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -32,6 +32,96 @@ import (
 )
 
 /*
+ * Errors
+ */
+const (
+       ErrorNonspecific                  = int(C.ERROR_NONSPECIFIC)
+       ErrorVersion                      = int(C.ERROR_VERSION)
+       ErrorFail                         = int(C.ERROR_FAIL)
+       ErrorNi                           = int(C.ERROR_NI)
+       ErrorNomem                        = int(C.ERROR_NOMEM)
+       ErrorInval                        = int(C.ERROR_INVAL)
+       ErrorBadfail                      = int(C.ERROR_BADFAIL)
+       ErrorGuestTimedout                = int(C.ERROR_GUEST_TIMEDOUT)
+       ErrorTimedout                     = int(C.ERROR_TIMEDOUT)
+       ErrorNoparavirt                   = int(C.ERROR_NOPARAVIRT)
+       ErrorNotReady                     = int(C.ERROR_NOT_READY)
+       ErrorOseventRegFail               = int(C.ERROR_OSEVENT_REG_FAIL)
+       ErrorBufferfull                   = int(C.ERROR_BUFFERFULL)
+       ErrorUnknownChild                 = int(C.ERROR_UNKNOWN_CHILD)
+       ErrorLockFail                     = int(C.ERROR_LOCK_FAIL)
+       ErrorJsonConfigEmpty              = int(C.ERROR_JSON_CONFIG_EMPTY)
+       ErrorDeviceExists                 = int(C.ERROR_DEVICE_EXISTS)
+       ErrorCheckpointDevopsDoesNotMatch = 
int(C.ERROR_CHECKPOINT_DEVOPS_DOES_NOT_MATCH)
+       ErrorCheckpointDeviceNotSupported = 
int(C.ERROR_CHECKPOINT_DEVICE_NOT_SUPPORTED)
+       ErrorVnumaConfigInvalid           = int(C.ERROR_VNUMA_CONFIG_INVALID)
+       ErrorDomainNotfound               = int(C.ERROR_DOMAIN_NOTFOUND)
+       ErrorAborted                      = int(C.ERROR_ABORTED)
+       ErrorNotfound                     = int(C.ERROR_NOTFOUND)
+       ErrorDomainDestroyed              = int(C.ERROR_DOMAIN_DESTROYED)
+       ErrorFeatureRemoved               = int(C.ERROR_FEATURE_REMOVED)
+)
+
+func createError(method string, cerrNum C.int) (err error) {
+       method += " %s"
+       errNum := int(cerrNum)
+       switch errNum {
+       case ErrorNonspecific:
+               err = fmt.Errorf(method, "ERROR_NONSPECIFIC")
+       case ErrorVersion:
+               err = fmt.Errorf(method, "ERROR_VERSION")
+       case ErrorFail:
+               err = fmt.Errorf(method, "ERROR_FAIL")
+       case ErrorNi:
+               err = fmt.Errorf(method, "ERROR_NI")
+       case ErrorNomem:
+               err = fmt.Errorf(method, "ERROR_NOMEM")
+       case ErrorInval:
+               err = fmt.Errorf(method, "ERROR_INVAL")
+       case ErrorBadfail:
+               err = fmt.Errorf(method, "ERROR_BADFAIL")
+       case ErrorGuestTimedout:
+               err = fmt.Errorf(method, "ERROR_GUEST_TIMEDOUT")
+       case ErrorNoparavirt:
+               err = fmt.Errorf(method, "ERROR_NOPARAVIRT")
+       case ErrorNotReady:
+               err = fmt.Errorf(method, "ERROR_NOT_READY")
+       case ErrorOseventRegFail:
+               err = fmt.Errorf(method, "ERROR_OSEVENT_REG_FAIL")
+       case ErrorBufferfull:
+               err = fmt.Errorf(method, "ERROR_BUFFERFULL")
+       case ErrorUnknownChild:
+               err = fmt.Errorf(method, "ERROR_UNKNOWN_CHILD")
+       case ErrorLockFail:
+               err = fmt.Errorf(method, "ERROR_LOCK_FAIL")
+       case ErrorJsonConfigEmpty:
+               err = fmt.Errorf(method, "ERROR_JSON_CONFIG_EMPTY")
+       case ErrorDeviceExists:
+               err = fmt.Errorf(method, "ERROR_DEVICE_EXISTS")
+       case ErrorCheckpointDevopsDoesNotMatch:
+               err = fmt.Errorf(method, 
"ERROR_CHECKPOINT_DEVOPS_DOES_NOT_MATCH")
+       case ErrorCheckpointDeviceNotSupported:
+               err = fmt.Errorf(method, 
"ERROR_CHECKPOINT_DEVICE_NOT_SUPPORTED")
+       case ErrorVnumaConfigInvalid:
+               err = fmt.Errorf(method, "ERROR_VNUMA_CONFIG_INVALID")
+       case ErrorDomainNotfound:
+               err = fmt.Errorf(method, "ERROR_DOMAIN_NOTFOUND")
+       case ErrorAborted:
+               err = fmt.Errorf(method, "ERROR_ABORTED")
+       case ErrorNotfound:
+               err = fmt.Errorf(method, "ERROR_NOTFOUND")
+       case ErrorDomainDestroyed:
+               err = fmt.Errorf(method, "ERROR_DOMAIN_DESTROYED")
+       case ErrorFeatureRemoved:
+               err = fmt.Errorf(method, "ERROR_FEATURE_REMOVED")
+       default:
+               err = fmt.Errorf(method, "error not found")
+       }
+       return
+
+}
+
+/*
  * Types: Builtins
  */
 type Context struct {
-- 
2.1.4

From 1012318772396a2e4219c9ffa4c57ccd443f42a1 Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dun...@citrix.com>
Date: Thu, 29 Dec 2016 19:49:02 +0000
Subject: [PATCH 3/7] tools/golang/xenlight: Add host-related functionality

Add calls for the following host-related functionality:
- libxl_get_max_cpus
- libxl_get_online_cpus
- libxl_get_max_nodes
- libxl_get_free_memory
- libxl_get_physinfo
- libxl_get_version_info

And include golang versions of the following structs:
 - libxl_physinfo
 - libxl_version_info
 - libxl_hwcap
---
 tools/golang/xenlight/xenlight.go | 193 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 193 insertions(+)

diff --git a/tools/golang/xenlight/xenlight.go 
b/tools/golang/xenlight/xenlight.go
index 677e5a5..05604c7 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -128,6 +128,68 @@ type Context struct {
        ctx *C.libxl_ctx
 }
 
+type Hwcap struct {
+       Hwcap []C.uint32_t
+}
+
+func hwcapCToGo(chwcap C.libxl_hwcap) (ghwcap Hwcap) {
+       // Alloc a Go slice for the bytes
+       size := 8
+       ghwcap.Hwcap = make([]C.uint32_t, size)
+
+       // Make a slice pointing to the C array
+       mapslice := (*[1 << 
30]C.uint32_t)(unsafe.Pointer(&chwcap[0]))[:size:size]
+
+       // And copy the C array into the Go array
+       copy(ghwcap.Hwcap, mapslice)
+
+       return
+}
+
+/*
+ * Types: IDL
+ *
+ * FIXME: Generate these automatically from the IDL
+ */
+type Physinfo struct {
+       Threads_per_core uint32
+       Cores_per_socket uint32
+
+       Max_cpu_id uint32
+       Nr_cpus    uint32
+       Cpu_khz    uint32
+
+       Total_pages         uint64
+       Free_pages          uint64
+       Scrub_pages         uint64
+       Outstanding_pages   uint64
+       Sharing_freed_pages uint64
+       Sharing_used_frames uint64
+
+       Nr_nodes uint32
+       Hw_cap   Hwcap
+
+       Cap_hvm          bool
+       Cap_hvm_directio bool
+}
+
+type VersionInfo struct {
+       Xen_version_major int
+       Xen_version_minor int
+       Xen_version_extra string
+       Compiler          string
+       Compile_by        string
+       Compile_domain    string
+       Compile_date      string
+       Capabilities      string
+       Changeset         string
+       Virt_start        uint64
+       Pagesize          int
+       Commandline       string
+       Build_id          string
+}
+
+
 /*
  * Context
  */
@@ -168,3 +230,134 @@ func (Ctx *Context) CheckOpen() (err error) {
        }
        return
 }
+
+//int libxl_get_max_cpus(libxl_ctx *ctx);
+func (Ctx *Context) GetMaxCpus() (maxCpus int, err error) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+
+       ret := C.libxl_get_max_cpus(Ctx.ctx)
+       //FIXME: proper error
+       if ret < 0 {
+               err = createError("libxl_get_max_cpus failed: ", ret)
+               return
+       }
+       maxCpus = int(ret)
+       return
+}
+
+//int libxl_get_online_cpus(libxl_ctx *ctx);
+func (Ctx *Context) GetOnlineCpus() (onCpus int, err error) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+
+       ret := C.libxl_get_online_cpus(Ctx.ctx)
+       //FIXME: proper error
+       if ret < 0 {
+               err = createError("libxl_get_online_cpus failed: ", ret)
+               return
+       }
+       onCpus = int(ret)
+       return
+}
+
+//int libxl_get_max_nodes(libxl_ctx *ctx);
+func (Ctx *Context) GetMaxNodes() (maxNodes int, err error) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+       ret := C.libxl_get_max_nodes(Ctx.ctx)
+       //FIXME: proper error
+       if ret < 0 {
+               err = createError("libxl_get_max_nodes failed: ", ret)
+               return
+       }
+       maxNodes = int(ret)
+       return
+}
+
+//int libxl_get_free_memory(libxl_ctx *ctx, uint64_t *memkb);
+func (Ctx *Context) GetFreeMemory() (memkb uint64, err error) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+       var cmem C.uint64_t
+       ret := C.libxl_get_free_memory(Ctx.ctx, &cmem)
+
+       if ret < 0 {
+               err = createError("libxl_get_free_memory failed: ", ret)
+               return
+       }
+
+       memkb = uint64(ret)
+       return
+
+}
+
+//int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
+func (Ctx *Context) GetPhysinfo() (physinfo *Physinfo, err error) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+       var cphys C.libxl_physinfo
+
+       ret := C.libxl_get_physinfo(Ctx.ctx, &cphys)
+
+       //FIXME: proper error
+       if ret < 0 {
+               err = createError("libxl_get_physinfo failed: ", ret)
+               return
+       }
+       physinfo = &Physinfo{}
+       physinfo.Threads_per_core = uint32(cphys.threads_per_core)
+       physinfo.Cores_per_socket = uint32(cphys.cores_per_socket)
+       physinfo.Max_cpu_id = uint32(cphys.max_cpu_id)
+       physinfo.Nr_cpus = uint32(cphys.nr_cpus)
+       physinfo.Cpu_khz = uint32(cphys.cpu_khz)
+       physinfo.Total_pages = uint64(cphys.total_pages)
+       physinfo.Free_pages = uint64(cphys.free_pages)
+       physinfo.Scrub_pages = uint64(cphys.scrub_pages)
+       physinfo.Outstanding_pages = uint64(cphys.scrub_pages)
+       physinfo.Sharing_freed_pages = uint64(cphys.sharing_freed_pages)
+       physinfo.Sharing_used_frames = uint64(cphys.sharing_used_frames)
+       physinfo.Nr_nodes = uint32(cphys.nr_nodes)
+       physinfo.Hw_cap = hwcapCToGo(cphys.hw_cap)
+       physinfo.Cap_hvm = bool(cphys.cap_hvm)
+       physinfo.Cap_hvm_directio = bool(cphys.cap_hvm_directio)
+
+       return
+}
+
+//const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx);
+func (Ctx *Context) GetVersionInfo() (info *VersionInfo, err error) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+
+       var cinfo *C.libxl_version_info
+
+       cinfo = C.libxl_get_version_info(Ctx.ctx)
+
+       info = &VersionInfo{}
+       info.Xen_version_major = int(cinfo.xen_version_major)
+       info.Xen_version_minor = int(cinfo.xen_version_minor)
+       info.Xen_version_extra = C.GoString(cinfo.xen_version_extra)
+       info.Compiler = C.GoString(cinfo.compiler)
+       info.Compile_by = C.GoString(cinfo.compile_by)
+       info.Compile_domain = C.GoString(cinfo.compile_domain)
+       info.Compile_date = C.GoString(cinfo.compile_date)
+       info.Capabilities = C.GoString(cinfo.capabilities)
+       info.Changeset = C.GoString(cinfo.changeset)
+       info.Virt_start = uint64(cinfo.virt_start)
+       info.Pagesize = int(cinfo.pagesize)
+
+       return
+}
-- 
2.1.4

From dcadedf83b219755994af123e2ee0ec49db85445 Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dun...@citrix.com>
Date: Thu, 29 Dec 2016 19:54:10 +0000
Subject: [PATCH 4/7] golang/xenlight: Implement libxl_get_gomainfinfo and
 libxl_domain_unpause

Signed-off-by: George Dunlap <george.dun...@citrix.com>
---
 tools/golang/xenlight/xenlight.go | 91 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/tools/golang/xenlight/xenlight.go 
b/tools/golang/xenlight/xenlight.go
index 05604c7..96a6952 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -124,6 +124,12 @@ func createError(method string, cerrNum C.int) (err error) 
{
 /*
  * Types: Builtins
  */
+type Domid uint32
+
+type MemKB uint64
+
+type Uuid C.libxl_uuid
+
 type Context struct {
        ctx *C.libxl_ctx
 }
@@ -189,6 +195,29 @@ type VersionInfo struct {
        Build_id          string
 }
 
+type Dominfo struct {
+       Uuid       Uuid
+       Domid      Domid
+       Running    bool
+       Blocked    bool
+       Paused     bool
+       Shutdown   bool
+       Dying      bool
+       Never_stop bool
+
+       Shutdown_reason   int32 // FIXME shutdown_reason enumeration
+       Outstanding_memkb MemKB
+       Current_memkb     MemKB
+       Shared_memkb      MemKB
+       Paged_memkb       MemKB
+       Max_memkb         MemKB
+       Cpu_time          time.Duration
+       Vcpu_max_id       uint32
+       Vcpu_online       uint32
+       Cpupool           uint32
+       Domain_type       int32 //FIXME libxl_domain_type enumeration
+
+}
 
 /*
  * Context
@@ -361,3 +390,65 @@ func (Ctx *Context) GetVersionInfo() (info *VersionInfo, 
err error) {
 
        return
 }
+
+//int libxl_domain_info(libxl_ctx*, libxl_dominfo *info_r, uint32_t domid);
+func (Ctx *Context) DomainInfo(Id Domid) (di *Dominfo, err error) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+
+       var cdi C.libxl_dominfo
+
+       ret := C.libxl_domain_info(Ctx.ctx, unsafe.Pointer(&cdi), 
C.uint32_t(Id))
+
+       // FIXME: proper error
+       if ret != 0 {
+               err = createError("libxl_domain_info failed: ", ret)
+               return
+       }
+
+       // We could consider having this boilerplate generated by the
+       // idl, in a function like this:
+       //
+       // di = translateCdomaininfoToGoDomaininfo(cdi)
+       di = &Dominfo{}
+       di.Uuid = Uuid(cdi.uuid)
+       di.Domid = Domid(cdi.domid)
+       di.Running = bool(cdi.running)
+       di.Blocked = bool(cdi.blocked)
+       di.Paused = bool(cdi.paused)
+       di.Shutdown = bool(cdi.shutdown)
+       di.Dying = bool(cdi.dying)
+       di.Never_stop = bool(cdi.never_stop)
+       di.Shutdown_reason = int32(cdi.shutdown_reason)
+       di.Outstanding_memkb = MemKB(cdi.outstanding_memkb)
+       di.Current_memkb = MemKB(cdi.current_memkb)
+       di.Shared_memkb = MemKB(cdi.shared_memkb)
+       di.Paged_memkb = MemKB(cdi.paged_memkb)
+       di.Max_memkb = MemKB(cdi.max_memkb)
+       di.Cpu_time = time.Duration(cdi.cpu_time)
+       di.Vcpu_max_id = uint32(cdi.vcpu_max_id)
+       di.Vcpu_online = uint32(cdi.vcpu_online)
+       di.Cpupool = uint32(cdi.cpupool)
+       di.Domain_type = int32(cdi.domain_type)
+
+       return
+}
+
+//int libxl_domain_unpause(libxl_ctx *ctx, uint32_t domid);
+func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+
+       ret := C.libxl_domain_unpause(Ctx.ctx, C.uint32_t(Id))
+
+       if ret != 0 {
+               //FIXME: proper error
+               err = createError("libxl_domain_unpause failed: ", ret)
+       }
+       return
+}
+
-- 
2.1.4

From 36ea15d6175781c48afee71c0fc4c2ca99f7e084 Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dun...@citrix.com>
Date: Thu, 29 Dec 2016 20:01:27 +0000
Subject: [PATCH 5/7] golang/xenlight: Implement libxl_bitmap and helper
 operations

Implement Bitmap type, along with helper operations.

The Bitmap type is implemented internally in a way which makes it easy
to copy into and outof the C libxl_bitmap type.

Signed-off-by: George Dunlap <george.dun...@citrix.com>
---
 tools/golang/xenlight/xenlight.go | 167 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 167 insertions(+)

diff --git a/tools/golang/xenlight/xenlight.go 
b/tools/golang/xenlight/xenlight.go
index 96a6952..b1384b0 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -152,6 +152,20 @@ func hwcapCToGo(chwcap C.libxl_hwcap) (ghwcap Hwcap) {
        return
 }
 
+// typedef struct {
+//     uint32_t size;          /* number of bytes in map */
+//     uint8_t *map;
+// } libxl_bitmap;
+
+// Implement the Go bitmap type such that the underlying data can
+// easily be copied in and out.  NB that we still have to do copies
+// both directions, because cgo runtime restrictions forbid passing to
+// a C function a pointer to a Go-allocated structure which contains a
+// pointer.
+type Bitmap struct {
+       bitmap []C.uint8_t
+}
+
 /*
  * Types: IDL
  *
@@ -220,6 +234,159 @@ type Dominfo struct {
 }
 
 /*
+ * Bitmap operations
+ */
+
+// Return a Go bitmap which is a copy of the referred C bitmap.
+func bitmapCToGo(cbm C.libxl_bitmap) (gbm Bitmap) {
+       // Alloc a Go slice for the bytes
+       size := int(cbm.size)
+       gbm.bitmap = make([]C.uint8_t, size)
+
+       // Make a slice pointing to the C array
+       mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
+
+       // And copy the C array into the Go array
+       copy(gbm.bitmap, mapslice)
+
+       return
+}
+
+// Must be C.libxl_bitmap_dispose'd of afterwards
+func bitmapGotoC(gbm Bitmap) (cbm C.libxl_bitmap) {
+       C.libxl_bitmap_init(&cbm)
+
+       size := len(gbm.bitmap)
+       cbm._map = (*C.uint8_t)(C.malloc(C.size_t(size)))
+       cbm.size = C.uint32_t(size)
+       if cbm._map == nil {
+               panic("C.calloc failed!")
+       }
+
+       // Make a slice pointing to the C array
+       mapslice := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
+
+       // And copy the Go array into the C array
+       copy(mapslice, gbm.bitmap)
+
+       return
+}
+
+func (bm *Bitmap) Test(bit int) bool {
+       ubit := uint(bit)
+       if bit > bm.Max() || bm.bitmap == nil {
+               return false
+       }
+
+       return (bm.bitmap[bit/8] & (1 << (ubit & 7))) != 0
+}
+
+func (bm *Bitmap) Set(bit int) {
+       ibit := bit / 8
+       if ibit+1 > len(bm.bitmap) {
+               bm.bitmap = append(bm.bitmap, make([]C.uint8_t, 
ibit+1-len(bm.bitmap))...)
+       }
+
+       bm.bitmap[ibit] |= 1 << (uint(bit) & 7)
+}
+
+func (bm *Bitmap) SetRange(start int, end int) {
+       for i := start; i <= end; i++ {
+               bm.Set(i)
+       }
+}
+
+func (bm *Bitmap) Clear(bit int) {
+       ubit := uint(bit)
+       if bit > bm.Max() || bm.bitmap == nil {
+               return
+       }
+
+       bm.bitmap[bit/8] &= ^(1 << (ubit & 7))
+}
+
+func (bm *Bitmap) ClearRange(start int, end int) {
+       for i := start; i <= end; i++ {
+               bm.Clear(i)
+       }
+}
+
+func (bm *Bitmap) Max() int {
+       return len(bm.bitmap)*8 - 1
+}
+
+func (bm *Bitmap) IsEmpty() bool {
+       for i := 0; i < len(bm.bitmap); i++ {
+               if bm.bitmap[i] != 0 {
+                       return false
+               }
+       }
+       return true
+}
+
+func (a Bitmap) And(b Bitmap) (c Bitmap) {
+       var max, min int
+       if len(a.bitmap) > len(b.bitmap) {
+               max = len(a.bitmap)
+               min = len(b.bitmap)
+       } else {
+               max = len(b.bitmap)
+               min = len(a.bitmap)
+       }
+       c.bitmap = make([]C.uint8_t, max)
+
+       for i := 0; i < min; i++ {
+               c.bitmap[i] = a.bitmap[i] & b.bitmap[i]
+       }
+       return
+}
+
+func (bm Bitmap) String() (s string) {
+       lastOnline := false
+       crange := false
+       printed := false
+       var i int
+       /// --x-xxxxx-x -> 2,4-8,10
+       /// --x-xxxxxxx -> 2,4-10
+       for i = 0; i <= bm.Max(); i++ {
+               if bm.Test(i) {
+                       if !lastOnline {
+                               // Switching offline -> online, print this cpu
+                               if printed {
+                                       s += ","
+                               }
+                               s += fmt.Sprintf("%d", i)
+                               printed = true
+                       } else if !crange {
+                               // last was online, but we're not in a range; 
print -
+                               crange = true
+                               s += "-"
+                       } else {
+                               // last was online, we're in a range,  nothing 
else to do
+                       }
+                       lastOnline = true
+               } else {
+                       if lastOnline {
+                               // Switching online->offline; do we need to end 
a range?
+                               if crange {
+                                       s += fmt.Sprintf("%d", i-1)
+                               }
+                       }
+                       lastOnline = false
+                       crange = false
+               }
+       }
+       if lastOnline {
+               // Switching online->offline; do we need to end a range?
+               if crange {
+                       s += fmt.Sprintf("%d", i-1)
+               }
+       }
+
+       return
+}
+
+/*
  * Context
  */
 var Ctx Context
-- 
2.1.4

From 272e37b66bfc206c5da5acb6772df8eb4e16e9d2 Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dun...@citrix.com>
Date: Thu, 29 Dec 2016 20:04:20 +0000
Subject: [PATCH 6/7] golang/xenlight: Implement libxl_scheduler enumeration

Include both constants and a Stringification.

Signed-off-by: George Dunlap <george.dun...@citrix.com>
---
 tools/golang/xenlight/xenlight.go | 63 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/tools/golang/xenlight/xenlight.go 
b/tools/golang/xenlight/xenlight.go
index b1384b0..31ce365 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -233,6 +233,69 @@ type Dominfo struct {
 
 }
 
+// # Consistent with values defined in domctl.h
+// # Except unknown which we have made up
+// libxl_scheduler = Enumeration("scheduler", [
+//     (0, "unknown"),
+//     (4, "sedf"),
+//     (5, "credit"),
+//     (6, "credit2"),
+//     (7, "arinc653"),
+//     (8, "rtds"),
+//     ])
+type Scheduler int
+
+var (
+       SchedulerUnknown  Scheduler = C.LIBXL_SCHEDULER_UNKNOWN
+       SchedulerSedf     Scheduler = C.LIBXL_SCHEDULER_SEDF
+       SchedulerCredit   Scheduler = C.LIBXL_SCHEDULER_CREDIT
+       SchedulerCredit2  Scheduler = C.LIBXL_SCHEDULER_CREDIT2
+       SchedulerArinc653 Scheduler = C.LIBXL_SCHEDULER_ARINC653
+       SchedulerRTDS     Scheduler = C.LIBXL_SCHEDULER_RTDS
+)
+
+// const char *libxl_scheduler_to_string(libxl_scheduler p);
+func (s Scheduler) String() string {
+       cs := C.libxl_scheduler_to_string(C.libxl_scheduler(s))
+       // No need to free const return value
+
+       return C.GoString(cs)
+}
+
+// int libxl_scheduler_from_string(const char *s, libxl_scheduler *e);
+func (s *Scheduler) FromString(gstr string) (err error) {
+       cstr := C.CString(gstr)
+       defer C.free(unsafe.Pointer(cstr))
+
+       var cs C.libxl_scheduler
+       ret := C.libxl_scheduler_from_string(cstr, &cs)
+       if ret != 0 {
+               //FIXME: proper error
+               err = createError("libxl_scheduler_from_string: ", ret)
+               return
+       }
+
+       *s = Scheduler(cs)
+       return
+}
+
+func SchedulerFromString(name string) (s Scheduler, err error) {
+       cname := C.CString(name)
+       defer C.free(unsafe.Pointer(cname))
+
+       var cs C.libxl_scheduler
+
+       ret := C.libxl_scheduler_from_string(cname, &cs)
+       if ret != 0 {
+               //FIXME: proper error
+               err = createError("libxl_scheduler_from_string failed: ", ret)
+               return
+       }
+
+       s = Scheduler(cs)
+
+       return
+}
 /*
  * Bitmap operations
  */
-- 
2.1.4

From 5325d67694900fe38a35a755bd0048020164cb31 Mon Sep 17 00:00:00 2001
From: George Dunlap <george.dun...@citrix.com>
Date: Thu, 29 Dec 2016 20:08:44 +0000
Subject: [PATCH 7/7] golang/xenlight: Implement cpupool operations

Also include some useful "Utility" functions:
 - CpupoolFindByName
 - CpupoolMakeFree

Still need to implement the following functions:
 libxl_cpupool_rename
 libxl_cpupool_cpuadd_node
 libxl_cpupool_cpuremove_node
 libxl_cpupool_movedomain

Signed-off-by: George Dunlap <george.dun...@citrix.com>
---
 tools/golang/xenlight/xenlight.go | 244 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 244 insertions(+)

diff --git a/tools/golang/xenlight/xenlight.go 
b/tools/golang/xenlight/xenlight.go
index 31ce365..e3d69ca 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -233,6 +233,32 @@ type Dominfo struct {
 
 }
 
+// libxl_cpupoolinfo = Struct("cpupoolinfo", [
+//     ("poolid",      uint32),
+//     ("pool_name",   string),
+//     ("sched",       libxl_scheduler),
+//     ("n_dom",       uint32),
+//     ("cpumap",      libxl_bitmap)
+//     ], dir=DIR_OUT)
+
+type CpupoolInfo struct {
+       Poolid      uint32
+       PoolName    string
+       Scheduler   Scheduler
+       DomainCount int
+       Cpumap      Bitmap
+}
+
+func translateCpupoolInfoCToGo(cci C.libxl_cpupoolinfo) (gci CpupoolInfo) {
+       gci.Poolid = uint32(cci.poolid)
+       gci.PoolName = C.GoString(cci.pool_name)
+       gci.Scheduler = Scheduler(cci.sched)
+       gci.DomainCount = int(cci.n_dom)
+       gci.Cpumap = bitmapCToGo(cci.cpumap)
+
+       return
+}
+
 // # Consistent with values defined in domctl.h
 // # Except unknown which we have made up
 // libxl_scheduler = Enumeration("scheduler", [
@@ -296,6 +322,7 @@ func SchedulerFromString(name string) (s Scheduler, err 
error) {
 
        return
 }
+
 /*
  * Bitmap operations
  */
@@ -682,3 +709,220 @@ func (Ctx *Context) DomainUnpause(Id Domid) (err error) {
        return
 }
 
+// libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx*, int *nb_pool_out);
+// void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nb_pool);
+func (Ctx *Context) ListCpupool() (list []CpupoolInfo) {
+       err := Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+
+       var nbPool C.int
+
+       c_cpupool_list := C.libxl_list_cpupool(Ctx.ctx, &nbPool)
+
+       defer C.libxl_cpupoolinfo_list_free(c_cpupool_list, nbPool)
+
+       if int(nbPool) == 0 {
+               return
+       }
+
+       // Magic
+       cpupoolListSlice := (*[1 << 
30]C.libxl_cpupoolinfo)(unsafe.Pointer(c_cpupool_list))[:nbPool:nbPool]
+
+       for i := range cpupoolListSlice {
+               info := translateCpupoolInfoCToGo(cpupoolListSlice[i])
+
+               list = append(list, info)
+       }
+
+       return
+}
+
+// int libxl_cpupool_info(libxl_ctx *ctx, libxl_cpupoolinfo *info, uint32_t 
poolid);
+func (Ctx *Context) CpupoolInfo(Poolid uint32) (pool CpupoolInfo) {
+       err := Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+
+       var c_cpupool C.libxl_cpupoolinfo
+
+       ret := C.libxl_cpupool_info(Ctx.ctx, &c_cpupool, C.uint32_t(Poolid))
+       //FIXME: proper error
+       if ret != 0 {
+               err = createError("libxl_cpupool_info failed: ", ret)
+               return
+       }
+       defer C.libxl_cpupoolinfo_dispose(&c_cpupool)
+
+       pool = translateCpupoolInfoCToGo(c_cpupool)
+
+       return
+}
+
+// int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
+//                          libxl_scheduler sched,
+//                          libxl_bitmap cpumap, libxl_uuid *uuid,
+//                          uint32_t *poolid);
+// FIXME: uuid
+// FIXME: Setting poolid
+func (Ctx *Context) CpupoolCreate(Name string, Scheduler Scheduler, Cpumap 
Bitmap) (err error, Poolid uint32) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+
+       poolid := C.uint32_t(0)
+       name := C.CString(Name)
+       defer C.free(unsafe.Pointer(name))
+
+       // For now, just do what xl does, and make a new uuid every time we 
create the pool
+       var uuid C.libxl_uuid
+       C.libxl_uuid_generate(&uuid)
+
+       cbm := bitmapGotoC(Cpumap)
+       defer C.libxl_bitmap_dispose(&cbm)
+
+       ret := C.libxl_cpupool_create(Ctx.ctx, name, 
C.libxl_scheduler(Scheduler),
+               cbm, &uuid, &poolid)
+       // FIXME: Proper error
+       if ret != 0 {
+               err = createError("libxl_cpupool_create failed: ", ret)
+               return
+       }
+
+       Poolid = uint32(poolid)
+
+       return
+}
+
+// int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid);
+func (Ctx *Context) CpupoolDestroy(Poolid uint32) (err error) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+
+       ret := C.libxl_cpupool_destroy(Ctx.ctx, C.uint32_t(Poolid))
+       // FIXME: Proper error
+       if ret != 0 {
+               err = createError("libxl_cpupool_destroy failed: ", ret)
+               return
+       }
+
+       return
+}
+
+// int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu);
+func (Ctx *Context) CpupoolCpuadd(Poolid uint32, Cpu int) (err error) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+
+       ret := C.libxl_cpupool_cpuadd(Ctx.ctx, C.uint32_t(Poolid), C.int(Cpu))
+       // FIXME: Proper error
+       if ret != 0 {
+               err = createError("libxl_cpupool_cpuadd failed: ", ret)
+               return
+       }
+
+       return
+}
+
+// int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
+//                                 const libxl_bitmap *cpumap);
+func (Ctx *Context) CpupoolCpuaddCpumap(Poolid uint32, Cpumap Bitmap) (err 
error) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+
+       cbm := bitmapGotoC(Cpumap)
+       defer C.libxl_bitmap_dispose(&cbm)
+
+       ret := C.libxl_cpupool_cpuadd_cpumap(Ctx.ctx, C.uint32_t(Poolid), &cbm)
+       // FIXME: Proper error
+       if ret != 0 {
+               err = createError("libxl_cpupool_cpuadd_cpumap failed: ", ret)
+               return
+       }
+
+       return
+}
+
+// int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu);
+func (Ctx *Context) CpupoolCpuremove(Poolid uint32, Cpu int) (err error) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+
+       ret := C.libxl_cpupool_cpuremove(Ctx.ctx, C.uint32_t(Poolid), 
C.int(Cpu))
+       // FIXME: Proper error
+       if ret != 0 {
+               err = createError("libxl_cpupool_cpuremove failed: ", ret)
+               return
+       }
+
+       return
+}
+
+// int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
+//                                    const libxl_bitmap *cpumap);
+func (Ctx *Context) CpupoolCpuremoveCpumap(Poolid uint32, Cpumap Bitmap) (err 
error) {
+       err = Ctx.CheckOpen()
+       if err != nil {
+               return
+       }
+
+       cbm := bitmapGotoC(Cpumap)
+       defer C.libxl_bitmap_dispose(&cbm)
+
+       ret := C.libxl_cpupool_cpuremove_cpumap(Ctx.ctx, C.uint32_t(Poolid), 
&cbm)
+       // FIXME: Proper error
+       if ret != 0 {
+               err = createError("libxl_cpupool_cpuremove_cpumap failed: ", 
ret)
+               return
+       }
+
+       return
+}
+
+// int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid);
+// int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, 
int *cpus);
+// int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, 
int *cpus);
+// int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t 
domid);
+
+//
+// Utility functions
+//
+func (Ctx *Context) CpupoolFindByName(name string) (info CpupoolInfo, found 
bool) {
+       plist := Ctx.ListCpupool()
+
+       for i := range plist {
+               if plist[i].PoolName == name {
+                       found = true
+                       info = plist[i]
+                       return
+               }
+       }
+       return
+}
+
+func (Ctx *Context) CpupoolMakeFree(Cpumap Bitmap) (err error) {
+       plist := Ctx.ListCpupool()
+
+       for i := range plist {
+               var Intersection Bitmap
+               Intersection = Cpumap.And(plist[i].Cpumap)
+               if !Intersection.IsEmpty() {
+                       err = Ctx.CpupoolCpuremoveCpumap(plist[i].Poolid, 
Intersection)
+                       if err != nil {
+                               return
+                       }
+               }
+       }
+       return
+}
-- 
2.1.4

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

Reply via email to