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