mirror of
https://github.com/google/go-jsonnet.git
synced 2025-09-29 09:21:03 +02:00
issue-433 avoid keeping all the allocated handles forever by using map
and uintptr of the allocated object.
This commit is contained in:
parent
db2bf1e024
commit
fc188d008d
@ -82,7 +82,7 @@ func (i *importer) Import(importedFrom, importedPath string) (contents jsonnet.C
|
|||||||
return i.contentCache[foundHere], foundHere, nil
|
return i.contentCache[foundHere], foundHere, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var handles = handlesTable{}
|
var handles = newHandlesTable()
|
||||||
var versionString *C.char
|
var versionString *C.char
|
||||||
|
|
||||||
//export jsonnet_version
|
//export jsonnet_version
|
||||||
@ -106,12 +106,12 @@ func jsonnet_make() *C.struct_JsonnetVm {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return C.jsonnet_internal_make_vm_with_id(C.uint64_t(id))
|
return C.jsonnet_internal_make_vm_with_id(C.uintptr_t(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
//export jsonnet_destroy
|
//export jsonnet_destroy
|
||||||
func jsonnet_destroy(vmRef *C.struct_JsonnetVm) {
|
func jsonnet_destroy(vmRef *C.struct_JsonnetVm) {
|
||||||
if err := handles.free(uint64(vmRef.id)); err != nil {
|
if err := handles.free(uintptr(vmRef.id)); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err.Error())
|
fmt.Fprintln(os.Stderr, err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ func jsonnet_destroy(vmRef *C.struct_JsonnetVm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getVM(vmRef *C.struct_JsonnetVm) *vm {
|
func getVM(vmRef *C.struct_JsonnetVm) *vm {
|
||||||
ref, err := handles.get(uint64(vmRef.id))
|
ref, err := handles.get(uintptr(vmRef.id))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err.Error())
|
fmt.Fprintln(os.Stderr, err.Error())
|
||||||
@ -411,7 +411,7 @@ func jsonnet_json_destroy(vmRef *C.struct_JsonnetVm, v *C.struct_JsonnetJsonValu
|
|||||||
jsonnet_json_destroy(vmRef, child)
|
jsonnet_json_destroy(vmRef, child)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := handles.free(uint64(v.id)); err != nil {
|
if err := handles.free(uintptr(v.id)); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err.Error())
|
fmt.Fprintln(os.Stderr, err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
@ -427,11 +427,11 @@ func createJSONValue(vmRef *C.struct_JsonnetVm, val interface{}) *C.struct_Jsonn
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return C.jsonnet_internal_make_json_with_id(C.uint64_t(id))
|
return C.jsonnet_internal_make_json_with_id(C.uintptr_t(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getJSONValue(jsonRef *C.struct_JsonnetJsonValue) *jsonValue {
|
func getJSONValue(jsonRef *C.struct_JsonnetJsonValue) *jsonValue {
|
||||||
ref, err := handles.get(uint64(jsonRef.id))
|
ref, err := handles.get(uintptr(jsonRef.id))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err.Error())
|
fmt.Fprintln(os.Stderr, err.Error())
|
||||||
|
@ -2,11 +2,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxID = (1 << 63) - 1
|
|
||||||
|
|
||||||
// Because of Go GC, there are restrictions on keeping Go pointers in C.
|
// Because of Go GC, there are restrictions on keeping Go pointers in C.
|
||||||
// We cannot just pass *jsonnet.VM/JsonValue to C. So instead we use "handle" structs in C
|
// We cannot just pass *jsonnet.VM/JsonValue to C. So instead we use "handle" structs in C
|
||||||
// which refer to JsonnetVM/JsonnetJsonValue by a numeric id.
|
// which refer to JsonnetVM/JsonnetJsonValue by a numeric id.
|
||||||
@ -17,62 +15,45 @@ const maxID = (1 << 63) - 1
|
|||||||
|
|
||||||
// handlesTable is the set of active, valid Jsonnet allocated handles
|
// handlesTable is the set of active, valid Jsonnet allocated handles
|
||||||
type handlesTable struct {
|
type handlesTable struct {
|
||||||
objects []interface{}
|
handles map[uintptr]*handle
|
||||||
freedIDs []uint64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// errMaxNumberOfOpenHandles tells that there was an attempt to create more than maxID open handles
|
type handle struct {
|
||||||
var errMaxNumberOfOpenHandles = fmt.Errorf("maximum number of constructed Jsonnet handles exceeded (%d)", maxID)
|
ref interface{}
|
||||||
|
}
|
||||||
|
|
||||||
// errInvalidHandle tells that there was an attempt to dereference invalid handle ID
|
// errInvalidHandle tells that there was an attempt to dereference invalid handle ID
|
||||||
var errInvalidHandle = errors.New("invalid handle ID was provided")
|
var errInvalidHandle = errors.New("invalid handle ID was provided")
|
||||||
|
|
||||||
// make registers the new object as a handle and returns the corresponding ID
|
func newHandlesTable() handlesTable {
|
||||||
func (h *handlesTable) make(obj interface{}) (uint64, error) {
|
return handlesTable{
|
||||||
var id uint64
|
handles: make(map[uintptr]*handle),
|
||||||
|
|
||||||
if len(h.freedIDs) > 0 {
|
|
||||||
id, h.freedIDs = h.freedIDs[len(h.freedIDs)-1], h.freedIDs[:len(h.freedIDs)-1]
|
|
||||||
h.objects[id-1] = obj
|
|
||||||
} else {
|
|
||||||
id = uint64(len(h.objects) + 1)
|
|
||||||
|
|
||||||
if id > maxID {
|
|
||||||
return 0, errMaxNumberOfOpenHandles
|
|
||||||
}
|
|
||||||
|
|
||||||
h.objects = append(h.objects, obj)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make registers the new object as a handle and returns the corresponding ID
|
||||||
|
func (h *handlesTable) make(obj interface{}) (uintptr, error) {
|
||||||
|
entry := &handle{ref: obj}
|
||||||
|
id := uintptr(unsafe.Pointer(entry))
|
||||||
|
h.handles[id] = entry
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// free marks the given handle ID as unused
|
// free removes an object with the given ID
|
||||||
func (h *handlesTable) free(id uint64) error {
|
func (h *handlesTable) free(id uintptr) error {
|
||||||
if err := h.ensureValidID(id); err != nil {
|
if _, ok := h.handles[id]; !ok {
|
||||||
return err
|
return errInvalidHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
h.objects[id-1] = nil
|
delete(h.handles, id)
|
||||||
h.freedIDs = append(h.freedIDs, id)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// get returns the corresponding object for the provided ID
|
// get returns the corresponding object for the provided ID
|
||||||
func (h *handlesTable) get(id uint64) (interface{}, error) {
|
func (h *handlesTable) get(id uintptr) (interface{}, error) {
|
||||||
if err := h.ensureValidID(id); err != nil {
|
if _, ok := h.handles[id]; !ok {
|
||||||
return nil, err
|
return nil, errInvalidHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
return h.objects[id-1], nil
|
return h.handles[id].ref, nil
|
||||||
}
|
|
||||||
|
|
||||||
// ensureValidID returns an error if the given handle ID is invalid, otherwise returns nil
|
|
||||||
func (h *handlesTable) ensureValidID(id uint64) error {
|
|
||||||
if id == 0 || uint64(id) > uint64(len(h.objects)) {
|
|
||||||
return errInvalidHandle
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,17 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct JsonnetVm {
|
struct JsonnetVm {
|
||||||
uint64_t id;
|
uintptr_t id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JsonnetVm *jsonnet_internal_make_vm_with_id(uint64_t id);
|
struct JsonnetVm *jsonnet_internal_make_vm_with_id(uintptr_t id);
|
||||||
void jsonnet_internal_free_vm(struct JsonnetVm *x);
|
void jsonnet_internal_free_vm(struct JsonnetVm *x);
|
||||||
|
|
||||||
struct JsonnetJsonValue {
|
struct JsonnetJsonValue {
|
||||||
uint64_t id;
|
uintptr_t id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JsonnetJsonValue *jsonnet_internal_make_json_with_id(uint64_t id);
|
struct JsonnetJsonValue *jsonnet_internal_make_json_with_id(uintptr_t id);
|
||||||
void jsonnet_internal_free_json(struct JsonnetJsonValue *x);
|
void jsonnet_internal_free_json(struct JsonnetJsonValue *x);
|
||||||
|
|
||||||
typedef struct JsonnetJsonValue *JsonnetNativeCallback(void *ctx,
|
typedef struct JsonnetJsonValue *JsonnetNativeCallback(void *ctx,
|
||||||
|
@ -6,7 +6,7 @@ extern "C" {
|
|||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JsonnetVm *jsonnet_internal_make_vm_with_id(uint64_t id) {
|
struct JsonnetVm *jsonnet_internal_make_vm_with_id(uintptr_t id) {
|
||||||
JsonnetVm *vm = new JsonnetVm();
|
JsonnetVm *vm = new JsonnetVm();
|
||||||
vm->id = id;
|
vm->id = id;
|
||||||
return vm;
|
return vm;
|
||||||
@ -16,7 +16,7 @@ void jsonnet_internal_free_vm(struct JsonnetVm *x) {
|
|||||||
delete(x);
|
delete(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JsonnetJsonValue *jsonnet_internal_make_json_with_id(uint64_t id) {
|
struct JsonnetJsonValue *jsonnet_internal_make_json_with_id(uintptr_t id) {
|
||||||
JsonnetJsonValue *json = new JsonnetJsonValue();
|
JsonnetJsonValue *json = new JsonnetJsonValue();
|
||||||
json->id = id;
|
json->id = id;
|
||||||
return json;
|
return json;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user