Repository: go
Issue: proposal: C API for the runtime
Labels: Proposal,Proposal-Hold

# Purpose

This is a proposal for a basic C API for the runtime.  It allows for non-Go main programs and for using specially written Go libraries from any language that can call C functions, with a few additional features beyond what are currently available by `buildmode=c-shared`.  This will be a new buildmode.
# Background

Go can call almost any C function via CGo.  However, the ability to have a non-Go main program is much more limited.  Go does have `buildmode=c-shared`, but it is limited by #11100 and also does not allow for useful features like passing `GOMAXPROCS` other than as an environment variable.
# Goals
- Allow for writing programs in a mixture of Go and another language, such that Go is not necessarily the language in which the program's entry point is written.
- Allow for writing a a library partly or completely in Go for use by another language.
- Provide handles that can passed to C and which can refer to any Go object.
# Non-Goals
- Allowing arbitrary Go functions to be called from C
- Allowing C code to manipulate arbitrary Go data structures.
# The API
## Ground rules.

The entire API is provided in a single C header file, `goapi.h`.

Unless otherwise specified, any function can be called from multiple threads simultaneously.  However, a single pointer in the API cannot be passed to API functions in 2 or more threads simultaneously, unless both functions take pointers to `const` data.
## The API itself

``` c
int go_runtime_init(char * const* errormsg, ssize_t *already_initialized, const char * const *options, const void * const* arguments);
```

Initializes the Go runtime.  Must be called before calling any other Go function.  Thread-safe and may be called multiple times.

`options` is a pointer to an array of NUL-terminated strings.  Each string corresponds to a matching `void*` in `arguments` that corresponds to a matching pointer, which points to a flag that can be used to configure the runtime.  Currently, the only string in `options` that is meaningful is `GOMAXPROCS`, which replaces the `GOMAXPROCS` environment variable: the corresponding `void*` must point to a `size_t*`.  All other values are reserved and must not be used.

If the defaults are OK, both `arguments` and `options` may be set to NULL.  They are ignored if the runtime is already initialized.

Returns 0 on success, a negative number on failure.
- On success, `*errormsg` is set to `NULL` and `*already_initialized` is set to the number of times the runtime has been initialized (including this one).  It is safe to set `errormsg` and/or `already_initialized` to NULL, in which case they are not accessed.
- On failure, `*errormsg` points to a NUL-terminated, human-readable error message, and `*already_initialized` holds a negative number.  Again, neither are written to if NULL.

``` c
int go_runtime_shutdown(void);
```

This function shuts down the runtime.  It must be called once for each call to `go_runtime_init`.  Only the last such call has any effect.

Once the number of calls to `go_runtime_shutdown` equals the number of calls to `go_runtime_init`, this function terminates all active goroutines and resets any signal handlers.

The following sentence may not be initially implemented:
  Afterwards, it is safe to `dlclose` the shared library containing the runtime, or to restart the runtime with `go_runtime_init`.

``` c
typedef struct Go_Handle *Go_Handle;
```

A handle to an arbitrary Go object.  Analogous to a Haskell stable pointer.  It stays valid even across garbage collections.

A `Go_Handle` is not guaranteed to point to valid memory.  Dereferencing it invokes undefined behavior.

``` c
void go_runtime_delete_handle(Go_Handle handle_to_be_freed);
```

Deletes the handle passed as argument, rendering it invalid and freeing all underlying resources.  After this function is called, the object the handle pointed to may be garbage collected if there are no more references to it.

``` c
Go_Handle go_runtime_duplicate_handle(Go_Handle handle_to_be_duplicated);
```

Duplicates the handle passed as argument.  The returned handle points to the same object as the original handle, but must be deallocated separately.

``` c
uint8_t go_runtime_are_identical_handles(Go_Handle handle1, Go_Handle handle2);
```

Tests if the 2 handles passed are identical.  Returns `true` if they point to the same object in memory.  Otherwise, returns `false`.
## The Go side

These are additional functions exposed from the runtime package.

``` go
type CHandle
```

The type of C handles to Go data.  When passed via CGo, becomes a `Go_Handle` on the C side.

May be accessed by multiple goroutines simultaneously.

``` go
func NewHandle(object interface {}) CHandle
```

Creates a handle to a Go object that can safely be passed to C.

``` go
func DuplicateHandle(handle CHandle) CHandle
```

Duplicates the handle.

``` go
func TestIfIdenticalHandles(handle1 CHandle, handle2 CHandle) bool
```

Tests if the 2 handles passed point to the same object; that is, if modifications of the object pointed to by one will affect the object pointed to by the other.

``` go
func DeallocateHandle(handle CHandle)
```

Deallocates the handle, rendering it invalid.

``` go
func DereferenceHandle(handle CHandle) interface {}
```

Dereferences the handle, returning the contained object.  If the handle is invalid, invokes undefined behavior.