// Copyright 2023 The Libc Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build linux && (amd64 || arm64 || loong64 || ppc64le || s390x || riscv64 || 386 || arm)

//go:generate go run generator.go

// Package libc is the runtime for programs generated by ccgo/v4 or later.
//
// # Version compatibility
//
// Read this. The package documentation states it at length; the short form is
// that this package is to ccgo what the runtime package is to Go, and that its
// version numbers therefore do not mean what semver says they mean.
//
// The API of this package, in particular the bits that directly support the
// ccgo compiler, may change in a way that is not backward compatible, and that
// can happen in a release that bumps only the patch or the minor number. If you
// have generated some Go code from C you should stick to the version of this
// package that you used at that time and was tested with your payload. The
// correct way to upgrade to a newer version of this package is to first
// recompile (C to Go) your code with a newer version of ccgo that depends on
// the new libc version.
//
// If you use C to Go translated code provided by others, stick to the version
// of libc that translated code shows in its go.mod file and do not upgrade the
// dependency just because a newer libc is tagged.
//
// This is of course unfortunate. However, it's somewhat similar to C code
// linked with a specific version of, say GNU libc. When such code asking for
// glibc5 is run on a system with glibc6, or vice versa, it will fail.
//
// As a particular example, if your project imports modernc.org/sqlite you
// should use the same libc version as seen in the go.mod file of the sqlite
// package.
//
// Such a mismatch used to show up as behaviour that quietly differed. Since
// LongjmpRetval became a struct, so that a region recovering a longjmp can tell
// whether it was the one targeted, it can also show up as code that refuses to
// compile. That is deliberate: the alternative to the build failing is a program
// that resumes at the wrong setjmp, and there is no way to fix that while
// keeping the old shape of the value.
//
// tl;dr: It is not always possible to fix ccgo bugs and/or improve performance
// of the ccgo transpiled code without occasionally making incompatible changes
// to this package.
//
// # Thread Local Storage
//
// A TLS instance represents a main thread or a thread created by
// Xpthread_create. A TLS instance is not safe for concurrent use by multiple
// goroutines.
//
// If a program starts the C main function, a TLS instance is created
// automatically and the goroutine entering main() is locked to the OS thread.
// The translated C code then may create other pthreads by calling
// Xpthread_create.
//
// If the translated C code is part of a library package, new TLS instances
// must be created manually in user/client code. The first TLS instance created
// will be the "main" libc thread, but it will be not locked to OS thread
// automatically. Any subsequently manually created TLS instances will call
// Xpthread_create, but without spawning a new goroutine.
//
// A manual call to Xpthread_create will create a new TLS instance automatically
// and spawn a new goroutine executing the thread function.

// Package libc provides run time support for programs generated by the
// [ccgo] C to Go transpiler, version 4 or later.
//
// # Concurrency
//
// Many C libc functions are not thread safe. Such functions are not safe
// for concurrent use by multiple goroutines in the Go translation as well.
//
// # Thread Local Storage
//
// C threads are modeled as Go goroutines.  Every such C thread, ie. a Go
// goroutine, must use its own Thread Local Storage instance implemented by the
// [TLS] type.
//
// # Signals
//
// Signal handling in translated C code is not coordinated with the Go runtime.
// This is probably the same as when running C code via CGo.
//
// # Environmental variables
//
// This package synchronizes its environ with the current Go environ lazily and
// only once.
//
// # libc API documentation copyright
//
// From [Linux man-pages Copyleft]
//
//	Permission is granted to make and distribute verbatim copies of this
//	manual provided the copyright notice and this permission notice are
//	preserved on all copies.
//
//	Permission is granted to copy and distribute modified versions of this
//	manual under the conditions for verbatim copying, provided that the
//	entire resulting derived work is distributed under the terms of a
//	permission notice identical to this one.
//
//	Since the Linux kernel and libraries are constantly changing, this
//	manual page may be incorrect or out-of-date. The author(s) assume no
//	responsibility for errors or omissions, or for damages resulting from
//	the use of the information contained herein. The author(s) may not have
//	taken the same level of care in the production of this manual, which is
//	licensed free of charge, as they might when working professionally.
//
//	Formatted or processed versions of this manual, if unaccompanied by the
//	source, must acknowledge the copyright and authors of this work.
//
// [Linux man-pages Copyleft]: https://spdx.org/licenses/Linux-man-pages-copyleft.html
// [ccgo]: http://modernc.org/ccgo/v4
package libc // import "modernc.org/libc"

import (
	"fmt"
	"io"
	"math"
	"math/rand"
	"os"
	"os/exec"
	gosignal "os/signal"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"sync"
	"sync/atomic"
	"time"
	"unsafe"

	guuid "github.com/google/uuid"
	"golang.org/x/sys/unix"
	"modernc.org/libc/uuid/uuid"
	"modernc.org/memory"
)

const (
	heapAlign = 16
	heapGuard = 16
)

var (
	_ error = (*MemAuditError)(nil)

	allocator   memory.Allocator
	allocatorMu sync.Mutex

	atExitMu sync.Mutex
	atExit   []func()

	tid atomic.Int32 // TLS Go ID

	Covered  = map[uintptr]struct{}{}
	CoveredC = map[string]struct{}{}
	coverPCs [1]uintptr //TODO not concurrent safe
)

func init() {
	nm, err := os.Executable()
	if err != nil {
		return
	}

	Xprogram_invocation_name = mustCString(nm)
	Xprogram_invocation_short_name = mustCString(filepath.Base(nm))
	X__libc.Fpage_size = Tsize_t(os.Getpagesize())
}

// RawMem64 represents the biggest uint64 array the runtime can handle.
type RawMem64 [unsafe.Sizeof(RawMem{}) / unsafe.Sizeof(uint64(0))]uint64

type MemAuditError struct {
	Caller  string
	Message string
}

func (e *MemAuditError) Error() string {
	return fmt.Sprintf("%s: %s", e.Caller, e.Message)
}

// Start executes C's main.
func Start(main func(*TLS, int32, uintptr) int32) {
	runtime.LockOSThread()
	if isMemBrk {
		defer func() {
			trc("==== PANIC")
			for _, v := range MemAudit() {
				trc("", v.Error())
			}
		}()
	}

	tls := NewTLS()
	Xexit(tls, main(tls, int32(len(os.Args)), mustAllocStrings(os.Args)))
}

func mustAllocStrings(a []string) (r uintptr) {
	nPtrs := len(a) + 1
	pPtrs := mustCalloc(Tsize_t(uintptr(nPtrs) * unsafe.Sizeof(uintptr(0))))
	ptrs := unsafe.Slice((*uintptr)(unsafe.Pointer(pPtrs)), nPtrs)
	nBytes := 0
	for _, v := range a {
		nBytes += len(v) + 1
	}
	pBytes := mustCalloc(Tsize_t(nBytes))
	b := unsafe.Slice((*byte)(unsafe.Pointer(pBytes)), nBytes)
	for i, v := range a {
		copy(b, v)
		b = b[len(v)+1:]
		ptrs[i] = pBytes
		pBytes += uintptr(len(v)) + 1
	}
	return pPtrs
}

func mustCString(s string) (r uintptr) {
	n := len(s)
	r = mustMalloc(Tsize_t(n + 1))
	copy(unsafe.Slice((*byte)(unsafe.Pointer(r)), n), s)
	*(*byte)(unsafe.Pointer(r + uintptr(n))) = 0
	return r
}

// CString returns a pointer to a zero-terminated version of s. The caller is
// responsible for freeing the allocated memory using Xfree.
func CString(s string) (uintptr, error) {
	n := len(s)
	p := Xmalloc(nil, Tsize_t(n)+1)
	if p == 0 {
		return 0, fmt.Errorf("CString: cannot allocate %d bytes", n+1)
	}

	copy(unsafe.Slice((*byte)(unsafe.Pointer(p)), n), s)
	*(*byte)(unsafe.Pointer(p + uintptr(n))) = 0
	return p, nil
}

func mustMalloc(sz Tsize_t) (r uintptr) {
	if r = Xmalloc(nil, sz); r != 0 || sz == 0 {
		return r
	}

	panic(todo("OOM"))
}

func mustCalloc(sz Tsize_t) (r uintptr) {
	if r := Xcalloc(nil, 1, sz); r != 0 || sz == 0 {
		return r
	}

	panic(todo("OOM"))
}

type tlsStackSlot struct {
	p  uintptr
	sz Tsize_t
}

// TLS emulates thread local storage. TLS is not safe for concurrent use by
// multiple goroutines.
type TLS struct {
	allocaStack         []int
	allocas             []uintptr
	jumpBuffers         []uintptr
	pendingSignals      chan os.Signal
	pthread             uintptr // *t__pthread
	pthreadCleanupItems []pthreadCleanupItem
	pthreadKeyValues    map[Tpthread_key_t]uintptr
	sigFlags            map[int32]int32 // sa_flags of sigHandlers installed by sigaction
	sigHandlers         map[int32]uintptr
	sp                  int
	stack               []tlsStackSlot

	ID int32

	checkSignals bool
	ownsPthread  bool
}

var __ccgo_environOnce sync.Once

// NewTLS returns a newly created TLS that must be eventually closed to prevent
// resource leaks.
func NewTLS() (r *TLS) {
	id := tid.Add(1)
	if id == 0 {
		id = tid.Add(1)
	}
	__ccgo_environOnce.Do(func() {
		Xenviron = mustAllocStrings(os.Environ())
	})
	pthread := mustMalloc(Tsize_t(unsafe.Sizeof(t__pthread{})))
	*(*t__pthread)(unsafe.Pointer(pthread)) = t__pthread{
		Flocale: uintptr(unsafe.Pointer(&X__libc.Fglobal_locale)),
		Fself:   pthread,
		Ftid:    id,
	}
	r = &TLS{
		ID:          id,
		ownsPthread: true,
		pthread:     pthread,
		sigFlags:    map[int32]int32{},
		sigHandlers: map[int32]uintptr{},
	}
	tlsRegistryMu.Lock()
	tlsByTID[id] = r
	tlsRegistryMu.Unlock()
	return r
}

var (
	// tlsRegistryMu guards tlsByTID, threadNames and the creation of
	// TLS.pendingSignals, the only TLS field another C thread reads.
	tlsRegistryMu sync.Mutex
	tlsByTID      = map[int32]*TLS{}
	threadNames   = map[uintptr]string{} // pthread_t -> name
)

// tlsByTid returns the TLS of the live C thread with the emulated tid, or nil.
func tlsByTid(tid int32) *TLS {
	tlsRegistryMu.Lock()

	defer tlsRegistryMu.Unlock()

	return tlsByTID[tid]
}

// signalChan returns tls.pendingSignals, creating it if necessary. The
// channel is created under tlsRegistryMu because killSignal reads it from
// another goroutine.
func (tls *TLS) signalChan() chan os.Signal {
	tlsRegistryMu.Lock()

	defer tlsRegistryMu.Unlock()

	if tls.pendingSignals == nil {
		tls.pendingSignals = make(chan os.Signal, 3)
	}
	return tls.pendingSignals
}

// killSignal implements tkill(2) directed at tls from another C thread. The
// signal is queued for delivery at the next check point of tls when it has
// registered for signals, otherwise it goes to the process.
func (tls *TLS) killSignal(sig int32) long {
	tlsRegistryMu.Lock()
	ch := tls.pendingSignals
	tlsRegistryMu.Unlock()
	if ch != nil {
		select {
		case ch <- unix.Signal(sig):
			return 0
		default:
			// Full, fall through.
		}
	}
	if err := unix.Kill(unix.Getpid(), unix.Signal(sig)); err != nil {
		return long(-err.(unix.Errno))
	}

	return 0
}

// StackSlots reports the number of tls stack slots currently in use.
func (tls *TLS) StackSlots() int {
	return tls.sp
}

// int *__errno_location(void)
func X__errno_location(tls *TLS) (r uintptr) {
	return tls.pthread + unsafe.Offsetof(t__pthread{}.Ferrno_val)
}

// int *__errno_location(void)
func X___errno_location(tls *TLS) (r uintptr) {
	return X__errno_location(tls)
}

func (tls *TLS) setErrno(n int32) {
	if tls == nil {
		return
	}

	*(*int32)(unsafe.Pointer(X__errno_location(tls))) = n
}

func (tls *TLS) String() string {
	return fmt.Sprintf("TLS#%v pthread=%x", tls.ID, tls.pthread)
}

// Alloc allocates n bytes in tls's local storage. Calls to Alloc() must be
// strictly paired with calls to TLS.Free on function exit. That also means any
// memory from Alloc must not be used after a function returns.
//
// The order matters. This is ok:
//
//	p := tls.Alloc(11)
//		q := tls.Alloc(22)
//		tls.Free(22)
//		// q is no more usable here.
//	tls.Free(11)
//	// p is no more usable here.
//
// This is not correct:
//
//	tls.Alloc(11)
//		tls.Alloc(22)
//		tls.Free(11)
//	tls.Free(22)
func (tls *TLS) Alloc(n0 int) (r uintptr) {
	// shrink	stats									speedtest1
	// -----------------------------------------------------------------------------------------------
	//    0		total  2,544, nallocs 107,553,070, nmallocs 25, nreallocs 107,553,045	10.984s
	//    1		total  2,544, nallocs 107,553,070, nmallocs 25, nreallocs  38,905,980	 9.597s
	//    2		total  2,616, nallocs 107,553,070, nmallocs 25, nreallocs  18,201,284	 9.206s
	//    3		total  2,624, nallocs 107,553,070, nmallocs 25, nreallocs  16,716,302	 9.155s
	//    4		total  2,624, nallocs 107,553,070, nmallocs 25, nreallocs  16,156,102	 9.398s
	//    8		total  3,408, nallocs 107,553,070, nmallocs 25, nreallocs  14,364,274	 9.198s
	//   16		total  3,976, nallocs 107,553,070, nmallocs 25, nreallocs   6,219,602	 8.910s
	// ---------------------------------------------------------------------------------------------
	//   32		total  5,120, nallocs 107,553,070, nmallocs 25, nreallocs   1,089,037	 8.836s
	// ---------------------------------------------------------------------------------------------
	//   64		total  6,520, nallocs 107,553,070, nmallocs 25, nreallocs       1,788	 8.420s
	//  128		total  8,848, nallocs 107,553,070, nmallocs 25, nreallocs       1,098	 8.833s
	//  256		total  8,848, nallocs 107,553,070, nmallocs 25, nreallocs       1,049	 9.508s
	//  512		total 33,336, nallocs 107,553,070, nmallocs 25, nreallocs          88	 8.667s
	// none		total 33,336, nallocs 107,553,070, nmallocs 25, nreallocs          88	 8.408s
	sp := tls.sp
	if stack := tls.stack; sp < len(stack) && stack[sp].sz >= Tsize_t(n0) /* && stack[sp].sz <= shrinkSegment*Tsize_t(n0) */ {
		// Segment shrinking is nice to have but Tcl does some dirty hacks in coroutine
		// handling that require stability of stack addresses, out of the C execution
		// model. Disabled.
		tls.sp = sp + 1
		return stack[sp].p
	}

	return tls.allocSlow(n0)
}

func (tls *TLS) allocSlow(n0 int) (r uintptr) {
	n := Tsize_t(n0)
	if tls.sp < len(tls.stack) {
		Xfree(tls, tls.stack[tls.sp].p)
		r = mustMalloc(n)
		tls.stack[tls.sp] = tlsStackSlot{p: r, sz: Xmalloc_usable_size(tls, r)}
		tls.sp++
		return r
	}

	r = mustMalloc(n)
	tls.stack = append(tls.stack, tlsStackSlot{p: r, sz: Xmalloc_usable_size(tls, r)})
	tls.sp++
	return r
}

// Free manages memory of the preceding TLS.Alloc()
func (tls *TLS) Free(n int) {
	//TODO shrink stacks if possible. Tcl is currently against.
	tls.sp--
	if !tls.checkSignals {
		return
	}

	tls.checkSignal()
}

func (tls *TLS) checkSignal() {
	select {
	case sig := <-tls.pendingSignals:
		tls.deliverSignal(int32(sig.(unix.Signal)))
	default:
		// nop
	}
}

// deliverSignal runs the handler installed for signum, if any, on the calling
// goroutine.
func (tls *TLS) deliverSignal(signum int32) {
	h, ok := tls.sigHandlers[signum]
	if !ok {
		return
	}

	switch h {
	case SIG_DFL:
		// nop
	case SIG_IGN:
		// nop
	default:
		flags := tls.sigFlags[signum]
		if uint32(flags)&SA_RESETHAND != 0 {
			Xsignal(tls, signum, SIG_DFL)
		}
		if flags&SA_SIGINFO != 0 {
			// void handler(int sig, siginfo_t *info, void *ctx)
			n := int(unsafe.Sizeof(Tsiginfo_t{}))
			info := tls.Alloc(n)
			*(*Tsiginfo_t)(unsafe.Pointer(info)) = Tsiginfo_t{Fsi_signo: signum}
			(*(*func(*TLS, int32, uintptr, uintptr))(unsafe.Pointer(&struct{ uintptr }{h})))(tls, signum, info, 0)
			tls.Free(n)
			return
		}

		(*(*func(*TLS, int32))(unsafe.Pointer(&struct{ uintptr }{h})))(tls, signum)
	}
}

// tid returns the emulated thread id of the C thread tls represents.
func (tls *TLS) tid() int32 {
	return (*t__pthread)(unsafe.Pointer(tls.pthread)).Ftid
}

// raiseSignal implements tkill(2) directed at the calling C thread, which is
// what raise() and pthread_kill(pthread_self(), sig) reduce to. A handler
// installed with signal() or sigaction() runs before the call returns, as it
// does for a single threaded C program. Without one the signal is sent to the
// process so the default action applies.
func (tls *TLS) raiseSignal(sig int32) long {
	switch h, ok := tls.sigHandlers[sig]; {
	case ok && h == SIG_IGN:
		return 0
	case ok && h != SIG_DFL:
		tls.deliverSignal(sig)
		return 0
	}

	if err := unix.Kill(unix.Getpid(), unix.Signal(sig)); err != nil {
		return long(-err.(unix.Errno))
	}

	return 0
}

func (tls *TLS) alloca(n Tsize_t) (r uintptr) {
	r = mustMalloc(n)
	tls.allocas = append(tls.allocas, r)
	return r
}

// AllocaEntry must be called early on function entry when the function calls
// or may call alloca(3).
func (tls *TLS) AllocaEntry() {
	tls.allocaStack = append(tls.allocaStack, len(tls.allocas))
}

// AllocaExit must be defer-called on function exit when the function calls or
// may call alloca(3).
func (tls *TLS) AllocaExit() {
	n := len(tls.allocaStack)
	x := tls.allocaStack[n-1]
	tls.allocaStack = tls.allocaStack[:n-1]
	for _, v := range tls.allocas[x:] {
		Xfree(tls, v)
	}
	tls.allocas = tls.allocas[:x]
}

func (tls *TLS) Close() {
	defer func() { *tls = TLS{} }()

	tlsRegistryMu.Lock()
	delete(tlsByTID, tls.ID)
	delete(threadNames, tls.pthread)
	tlsRegistryMu.Unlock()
	for _, v := range tls.allocas {
		Xfree(tls, v)
	}
	for _, v := range tls.stack /* shrink diabled[:tls.sp] */ {
		Xfree(tls, v.p)
	}
	if tls.ownsPthread {
		Xfree(tls, tls.pthread)
	}
}

// PushJumpBuffer arms jb, which stays armed until the matching PopJumpBuffer or
// until a Longjmp targets it. C keeps every jump buffer of a live frame valid, so
// more than one can be armed at a time and they need not be left in the order they
// were armed in.
func (tls *TLS) PushJumpBuffer(jb uintptr) {
	tls.jumpBuffers = append(tls.jumpBuffers, jb)
}

// LongjmpRetval is what Longjmp panics with. A panic unwinds through every setjmp
// region between the longjmp and its target, so a recovering region must compare
// JumpBuffer with its own and re-panic unless they are equal: recovering a longjmp
// aimed past it would resume at the wrong setjmp.
type LongjmpRetval struct {
	// JumpBuffer is the buffer the longjmp targeted, already disarmed.
	JumpBuffer uintptr
	// Val is what setjmp must appear to return, never zero.
	Val int32
}

// PopJumpBuffer disarms jb, which must be the most recently armed buffer still
// armed. Regions leave in the order they were entered, so anything else is a bug
// in the generated code rather than in the C being translated.
func (tls *TLS) PopJumpBuffer(jb uintptr) {
	n := len(tls.jumpBuffers)
	if n == 0 || tls.jumpBuffers[n-1] != jb {
		panic(todo("unsupported setjmp/longjmp usage"))
	}

	tls.jumpBuffers = tls.jumpBuffers[:n-1]
}

// Longjmp disarms jb and panics with a LongjmpRetval naming it. jb need not be the
// most recently armed buffer: C allows jumping past regions entered after the one
// being jumped to, and those regions disarm their own buffers as the panic unwinds
// through them. Of two regions sharing a buffer the innermost one is disarmed,
// which is the one C resumes at.
func (tls *TLS) Longjmp(jb uintptr, val int32) {
	i := len(tls.jumpBuffers) - 1
	for ; i >= 0 && tls.jumpBuffers[i] != jb; i-- {
	}
	if i < 0 {
		// Jumping to a buffer no setjmp armed, or to one whose region has been
		// left already, which C leaves undefined.
		panic(todo("unsupported setjmp/longjmp usage"))
	}

	tls.jumpBuffers = append(tls.jumpBuffers[:i], tls.jumpBuffers[i+1:]...)
	if val == 0 {
		val = 1
	}
	panic(LongjmpRetval{JumpBuffer: jb, Val: val})
}

// ============================================================================

func Xexit(tls *TLS, code int32) {
	//TODO atexit finalizers
	X__stdio_exit(tls)
	for i := len(atExit) - 1; i >= 0; i-- {
		atExit[i]()
	}
	atExitHandlersMu.Lock()
	for i := len(atExitHandlers) - 1; i >= 0; i-- {
		v := atExitHandlers[i]
		(*(*func(*TLS))(unsafe.Pointer(&struct{ uintptr }{v})))(tls)
	}
	os.Exit(int(code))
}

func _exit(tls *TLS, code int32) {
	Xexit(tls, code)
}

var abort Tsigaction

// abort dies by SIGABRT with the signal's default disposition, as musl's
// does. ___libc_sigaction records the SIG_DFL for os/signal only and leaves
// the Go runtime's SIGABRT handler in the kernel, which would print a
// goroutine dump to stderr and only then let the process die; resetSigDfl
// puts the kernel's default back so that the death is silent, with the core
// dump the resource limits allow, and a parent sees a child killed by SIGABRT
// with an empty stderr. sqlite's writecrash.test checks exactly that. The
// signal is sent thread-directed with tgkill, as the Go runtime's raise()
// does and as the netbsd Xabort explains: a process-directed kill(2) is
// asynchronous and the calling thread can run on before it lands. With
// SIG_DFL installed the kernel terminates the process in tgkill; the
// process-directed kill and the panic are unreachable fallbacks.
func Xabort(tls *TLS) {
	___libc_sigaction(tls, SIGABRT, uintptr(unsafe.Pointer(&abort)), 0)
	resetSigDfl(SIGABRT)
	unix.Tgkill(unix.Getpid(), unix.Gettid(), unix.Signal(SIGABRT))
	unix.Kill(unix.Getpid(), unix.Signal(SIGABRT))
	panic(todo("unrechable"))
}

// States of the C lock word *p, as in musl's __lock/__unlock.
const (
	lockFree      = 0 // Nobody holds the lock.
	lockHeld      = 1 // Held, no waiter has parked.
	lockContended = 2 // Held, a waiter may be parked.
)

// ___lock/___unlock emulate musl's __lock/__unlock, a mutual-exclusion lock over
// the opaque C lock word *p.
//
// All lock state lives in *p, exactly as it does in musl. That is a correctness
// requirement, not just fidelity to upstream: a caller may free the memory
// holding the word while the lock is held and never unlock it. musl's
// freeaddrinfo does precisely that, dropping the last aibuf reference under
// LOCK(b->lock) and calling free(b) instead of UNLOCK(b->lock). In C the state
// dies with the block, so a recycled, zero-initialized block starts out
// unlocked. Every lock word reachable here is either a zeroed package-level var
// or lives in Xcalloc'd memory, so that holds here too.
//
// Blocking uses a parking lot keyed by the word's address, standing in for the
// futex musl waits on. lockWait re-checks *p under lockParkMu, and ___unlock
// stores to *p before lockWake takes lockParkMu, so a release landing before the
// waiter parks is observed as a value change instead of being lost. Parking lot
// entries exist only while a goroutine is actually parked, so a lock abandoned
// with no waiter leaves nothing behind.
//
// Two earlier implementations each satisfied one half of that. The first kept an
// atomic fast path on *p plus a throwaway hand-off object in a map and lost
// wakeups when an unlocker reached the map before a contending locker had
// registered there (cznic/libc#51). The second moved all state into a
// process-global map keyed on the address, which made freeaddrinfo's abandoned
// lock permanent: the entry outlived the free, still locked, and the next caller
// handed that address wedged at zero CPU.

func ___lock(tls *TLS, p uintptr) {
	w := (*int32)(unsafe.Pointer(p))
	if atomic.CompareAndSwapInt32(w, lockFree, lockHeld) {
		return // Uncontended.
	}

	// Some other C thread holds p. The swap claims the lock if it turns out to be
	// free and otherwise records that its holder owes us a wake.
	for atomic.SwapInt32(w, lockContended) != lockFree {
		lockWait(p, lockContended)
	}
}

func ___unlock(tls *TLS, p uintptr) {
	if atomic.SwapInt32((*int32)(unsafe.Pointer(p)), lockFree) == lockContended {
		lockWake(p)
	}
}

// lockPark collects the goroutines parked on one lock word address, in
// arrival order. Every waiter has its own channel, so a wake can target one
// waiter and a waiter can leave on a timeout.
type lockPark struct {
	waiters []chan struct{}
}

var (
	lockParkMu sync.Mutex
	lockParked = map[uintptr]*lockPark{}
)

// lockWait parks the calling goroutine while *p is still val, standing in for
// musl's __futexwait.
func lockWait(p uintptr, val int32) {
	lockWaitTimeout(p, val, -1)
}

// lockWaitTimeout is lockWait with a timeout, none if it is negative. It
// reports false when the timeout expired before a wake arrived.
func lockWaitTimeout(p uintptr, val int32, timeout time.Duration) bool {
	lockParkMu.Lock()
	// Re-check under lockParkMu: ___unlock stores to *p before lockWake takes
	// lockParkMu, so a wake that would otherwise be delivered before we park shows
	// up here as a changed value.
	if atomic.LoadInt32((*int32)(unsafe.Pointer(p))) != val {
		lockParkMu.Unlock()
		return true
	}

	q := lockParked[p]
	if q == nil {
		q = &lockPark{}
		lockParked[p] = q
	}
	ch := make(chan struct{}, 1)
	q.waiters = append(q.waiters, ch)
	lockParkMu.Unlock()

	if timeout < 0 {
		<-ch
		return true
	}

	t := time.NewTimer(timeout)

	defer t.Stop()

	select {
	case <-ch:
		return true
	case <-t.C:
	}

	lockParkMu.Lock()

	defer lockParkMu.Unlock()

	// A wake may have arrived while the timer fired: it is then in ch, and the
	// waker has already removed us.
	select {
	case <-ch:
		return true
	default:
	}

	if q := lockParked[p]; q != nil {
		for i, v := range q.waiters {
			if v == ch {
				q.waiters = append(q.waiters[:i], q.waiters[i+1:]...)
				break
			}
		}
		if len(q.waiters) == 0 {
			delete(lockParked, p)
		}
	}
	return false
}

// lockWake releases one goroutine parked on p, if any, standing in for musl's
// __wake. Waking one suffices: whoever wakes either acquires p, and then owes
// the next wake when it unlocks, or re-marks p contended before parking again.
func lockWake(p uintptr) {
	lockWakeN(p, 1)
}

// lockWakeN releases up to cnt goroutines parked on p, all of them if cnt is
// negative.
func lockWakeN(p uintptr, cnt int32) {
	lockParkMu.Lock()

	defer lockParkMu.Unlock()

	q := lockParked[p]
	if q == nil {
		return
	}

	for len(q.waiters) != 0 && cnt != 0 {
		ch := q.waiters[0]
		q.waiters = q.waiters[1:]
		ch <- struct{}{}
		cnt--
	}
	if len(q.waiters) == 0 {
		delete(lockParked, p)
	}
}

// casInt32 is musl's a_cas: it stores s into *p if *p is t and returns the
// value *p had before.
func casInt32(p uintptr, t, s int32) int32 {
	w := (*int32)(unsafe.Pointer(p))
	for {
		old := atomic.LoadInt32(w)
		if old != t {
			return old
		}

		if atomic.CompareAndSwapInt32(w, t, s) {
			return t
		}
	}
}

// static inline void __wake(volatile void *addr, int cnt, int priv)
//
// The pthread_impl.h overlay declares __wake and __futexwait without a body,
// because a futex syscall would never wake a goroutine parked by lockWait.
func ___wake(tls *TLS, addr uintptr, cnt int32, priv int32) {
	lockWakeN(addr, cnt)
}

// static inline void __futexwait(volatile void *addr, int val, int priv)
func ___futexwait(tls *TLS, addr uintptr, val int32, priv int32) {
	lockWait(addr, val)
}

// int __timedwait_cp(volatile int *addr, int val, clockid_t clk, const struct timespec *at, int priv)
//
// Parks while *addr is val, until the absolute time at on clock clk when at
// is not null. Cancellation points are not implemented. See
// https://gitlab.com/cznic/libc/-/issues/55.
func ___timedwait_cp(tls *TLS, addr uintptr, val int32, clk Tclockid_t, at uintptr, priv int32) int32 {
	timeout := time.Duration(-1)
	if at != 0 {
		ts := (*Ttimespec)(unsafe.Pointer(at))
		if ts.Ftv_nsec < 0 || ts.Ftv_nsec >= 1e9 {
			return EINVAL
		}

		var now unix.Timespec
		if err := unix.ClockGettime(int32(clk), &now); err != nil {
			return EINVAL
		}

		secs := int64(ts.Ftv_sec) - int64(now.Sec)
		switch {
		case secs < 0:
			return ETIMEDOUT
		case secs > 1<<31:
			// Far enough to be no timeout at all.
		default:
			timeout = time.Duration(secs)*time.Second + time.Duration(int64(ts.Ftv_nsec)-int64(now.Nsec))
			if timeout <= 0 {
				return ETIMEDOUT
			}
		}
	}
	if !lockWaitTimeout(addr, val, timeout) {
		return ETIMEDOUT
	}

	return 0
}

func X__lockfile(tls *TLS, file uintptr) int32 {
	return ___lockfile(tls, file)
}

// int __lockfile(FILE *f)
//
// Transliterated from musl src/stdio/__lockfile.c, which the generator removes.
// The transpiled ftrylockfile, funlockfile and the locking getc/putc helpers
// operate on the same lock word with a_cas and a_swap, so the protocol must be
// kept exactly: the owner's tid, MAYBE_WAITERS when someone parked.
func ___lockfile(tls *TLS, file uintptr) int32 {
	p := file + unsafe.Offsetof(TFILE{}.Flock)
	tid := (*t__pthread)(unsafe.Pointer(___get_tp(tls))).Ftid
	owner := atomic.LoadInt32((*int32)(unsafe.Pointer(p)))
	if owner & ^int32(MAYBE_WAITERS) == tid {
		return 0
	}

	if casInt32(p, 0, tid) == 0 {
		return 1
	}

	for {
		owner = casInt32(p, 0, tid|MAYBE_WAITERS)
		if owner == 0 {
			return 1
		}

		if owner&MAYBE_WAITERS != 0 || casInt32(p, owner, owner|MAYBE_WAITERS) == owner {
			lockWait(p, owner|MAYBE_WAITERS)
		}
	}
}

func X__unlockfile(tls *TLS, file uintptr) {
	___unlockfile(tls, file)
}

// void __unlockfile(FILE *f)
func ___unlockfile(tls *TLS, file uintptr) {
	p := file + unsafe.Offsetof(TFILE{}.Flock)
	if atomic.SwapInt32((*int32)(unsafe.Pointer(p)), 0)&MAYBE_WAITERS != 0 {
		lockWake(p)
	}
}

// void __synccall(void (*func)(void *), void *ctx)
func ___synccall(tls *TLS, fn, ctx uintptr) {
	(*(*func(*TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{fn})))(tls, ctx)
}

// func ___randname(tls *TLS, template uintptr) (r1 uintptr) {
// 	bp := tls.Alloc(16)
// 	defer tls.Free(16)
// 	var i int32
// 	var r uint64
// 	var _ /* ts at bp+0 */ Ttimespec
// 	X__clock_gettime(tls, CLOCK_REALTIME, bp)
// 	goto _2
// _2:
// 	r = uint64((*(*Ttimespec)(unsafe.Pointer(bp))).Ftv_sec+(*(*Ttimespec)(unsafe.Pointer(bp))).Ftv_nsec) + uint64(tls.ID)*uint64(65537)
// 	i = 0
// 	for {
// 		if !(i < int32(6)) {
// 			break
// 		}
// 		*(*int8)(unsafe.Pointer(template + uintptr(i))) = int8(uint64('A') + r&uint64(15) + r&uint64(16)*uint64(2))
// 		goto _3
// 	_3:
// 		i++
// 		r >>= uint64(5)
// 	}
// 	return template
// }

// #include <time.h>
// #include <stdint.h>
// #include "pthread_impl.h"
//
// /* This assumes that a check for the
//
//	template size has already been made */
//
// char *__randname(char *template)
//
//	{
//		int i;
//		struct timespec ts;
//		unsigned long r;
//
//		__clock_gettime(CLOCK_REALTIME, &ts);
//		r = ts.tv_sec + ts.tv_nsec + __pthread_self()->tid * 65537UL;
//		for (i=0; i<6; i++, r>>=5)
//			template[i] = 'A'+(r&15)+(r&16)*2;
//
//		return template;
//	}
func ___randname(tls *TLS, template uintptr) (r1 uintptr) {
	var i int32
	ts := time.Now().UnixNano()
	r := uint64(ts) + uint64(tls.ID)*65537
	i = 0
	for {
		if !(i < int32(6)) {
			break
		}
		*(*int8)(unsafe.Pointer(template + uintptr(i))) = int8(uint64('A') + r&uint64(15) + r&uint64(16)*uint64(2))
		goto _3
	_3:
		i++
		r >>= uint64(5)
	}
	return template
}

func ___get_tp(tls *TLS) uintptr {
	return tls.pthread
}

func Xfork(t *TLS) int32 {
	if __ccgo_strace {
		trc("t=%v, (%v:)", t, origin(2))
	}
	t.setErrno(ENOSYS)
	return -1
}

func Xsignal(tls *TLS, signum int32, handler uintptr) (r uintptr) {
	r, tls.sigHandlers[signum] = tls.sigHandlers[signum], handler
	delete(tls.sigFlags, signum)
	switch handler {
	case SIG_DFL:
		gosignal.Reset(unix.Signal(signum))
	case SIG_IGN:
		gosignal.Ignore(unix.Signal(signum))
	default:
		ch := tls.signalChan()
		tls.checkSignals = true
		gosignal.Notify(ch, unix.Signal(signum))
	}
	return r
}

// int pthread_setname_np(pthread_t thread, const char *name)
//
// Emulated threads have no kernel thread of their own, so names are kept
// here instead of in /proc. See https://gitlab.com/cznic/libc/-/issues/55.
func Xpthread_setname_np(tls *TLS, thread uintptr, name uintptr) int32 {
	s := GoString(name)
	if len(s) > 15 {
		return ERANGE
	}

	tlsRegistryMu.Lock()
	threadNames[thread] = s
	tlsRegistryMu.Unlock()
	return 0
}

// int pthread_getname_np(pthread_t thread, char *name, size_t len)
//
// An unnamed thread reports the process name, as the kernel would.
func Xpthread_getname_np(tls *TLS, thread uintptr, name uintptr, len1 Tsize_t) int32 {
	if len1 < 16 {
		return ERANGE
	}

	tlsRegistryMu.Lock()
	s, ok := threadNames[thread]
	tlsRegistryMu.Unlock()
	if !ok {
		var buf [16]byte
		if err := unix.Prctl(unix.PR_GET_NAME, uintptr(unsafe.Pointer(&buf[0])), 0, 0, 0); err != nil {
			return int32(err.(unix.Errno))
		}

		n := 0
		for n < len(buf) && buf[n] != 0 {
			n++
		}
		s = string(buf[:n])
	}
	copy(unsafe.Slice((*byte)(unsafe.Pointer(name)), len(s)+1), s+"\x00")
	return 0
}

// int pthread_getcpuclockid(pthread_t t, clockid_t *clockid)
//
// The calling thread gets the CPU clock of the kernel thread it runs on.
// Other emulated threads have no kernel thread and hence no clock, which is
// reported as ESRCH.
func Xpthread_getcpuclockid(tls *TLS, t uintptr, clockid uintptr) int32 {
	if t != tls.pthread {
		return ESRCH
	}

	*(*Tclockid_t)(unsafe.Pointer(clockid)) = CLOCK_THREAD_CPUTIME_ID
	return 0
}

// int __libc_sigaction(int sig, const struct sigaction *sa, struct sigaction *old)
//
// The transpiled musl version installs the handler with the rt_sigaction
// syscall, which cannot work here: the handler and the restorer would be Go
// function values. The generator hides it and this version records the
// disposition the same way Xsignal does, delivering through os/signal and
// checkSignal. sa_mask and the flags other than SA_SIGINFO and SA_RESETHAND are
// ignored. See https://gitlab.com/cznic/libc/-/issues/53.
func ___libc_sigaction(tls *TLS, sig int32, sa, old uintptr) int32 {
	if old != 0 {
		h, ok := tls.sigHandlers[sig]
		if !ok {
			h = SIG_DFL
		}
		flags := tls.sigFlags[sig]
		*(*Tsigaction)(unsafe.Pointer(old)) = Tsigaction{}
		*(*uintptr)(unsafe.Pointer(old)) = h // sa_handler, sa_sigaction
		(*Tsigaction)(unsafe.Pointer(old)).Fsa_flags = flags
	}
	if sa != 0 {
		flags := (*Tsigaction)(unsafe.Pointer(sa)).Fsa_flags
		Xsignal(tls, sig, *(*uintptr)(unsafe.Pointer(sa)))
		tls.sigFlags[sig] = flags
	}
	return 0
}

var (
	atExitHandlersMu sync.Mutex
	atExitHandlers   []uintptr
)

func Xatexit(tls *TLS, func_ uintptr) (r int32) {
	atExitHandlersMu.Lock()
	atExitHandlers = append(atExitHandlers, func_)
	atExitHandlersMu.Unlock()
	return 0
}

var __sync_synchronize_dummy int32

// __sync_synchronize();
func X__sync_synchronize(t *TLS) {
	if __ccgo_strace {
		trc("t=%v, (%v:)", t, origin(2))
	}
	// Attempt to implement a full memory barrier without assembler.
	atomic.StoreInt32(&__sync_synchronize_dummy, atomic.LoadInt32(&__sync_synchronize_dummy)+1)
}

func Xdlopen(t *TLS, filename uintptr, flags int32) uintptr {
	if __ccgo_strace {
		trc("t=%v filename=%v flags=%v, (%v:)", t, filename, flags, origin(2))
	}
	return 0
}

func Xdlsym(t *TLS, handle, symbol uintptr) uintptr {
	if __ccgo_strace {
		trc("t=%v symbol=%v, (%v:)", t, symbol, origin(2))
	}
	return 0
}

var dlErrorMsg = []byte("not supported\x00")

func Xdlerror(t *TLS) uintptr {
	if __ccgo_strace {
		trc("t=%v, (%v:)", t, origin(2))
	}
	return uintptr(unsafe.Pointer(&dlErrorMsg[0]))
}

func Xdlclose(t *TLS, handle uintptr) int32 {
	if __ccgo_strace {
		trc("t=%v handle=%v, (%v:)", t, handle, origin(2))
	}
	panic(todo(""))
}

func Xsystem(t *TLS, command uintptr) int32 {
	if __ccgo_strace {
		trc("t=%v command=%v, (%v:)", t, command, origin(2))
	}
	s := GoString(command)
	if command == 0 {
		panic(todo(""))
	}

	cmd := exec.Command("sh", "-c", s)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err != nil {
		ps := err.(*exec.ExitError)
		return int32(ps.ExitCode())
	}

	return 0
}

func Xsched_yield(tls *TLS) int32 {
	runtime.Gosched()
	return 0
}

// AtExit will attempt to run f at process exit. The execution cannot be
// guaranteed, neither its ordering with respect to any other handlers
// registered by AtExit.
func AtExit(f func()) {
	atExitMu.Lock()
	atExit = append(atExit, f)
	atExitMu.Unlock()
}

func Bool64(b bool) int64 {
	if b {
		return 1
	}

	return 0
}

func Environ() uintptr {
	__ccgo_environOnce.Do(func() {
		Xenviron = mustAllocStrings(os.Environ())
	})
	return Xenviron
}

func EnvironP() uintptr {
	__ccgo_environOnce.Do(func() {
		Xenviron = mustAllocStrings(os.Environ())
	})
	return uintptr(unsafe.Pointer(&Xenviron))
}

// NewVaList is like VaList but automatically allocates the correct amount of
// memory for all of the items in args.
//
// The va_list return value is used to pass the constructed var args to var
// args accepting functions. The caller of NewVaList is responsible for freeing
// the va_list.
func NewVaList(args ...interface{}) (va_list uintptr) {
	return VaList(NewVaListN(len(args)), args...)
}

// NewVaListN returns a newly allocated va_list for n items. The caller of
// NewVaListN is responsible for freeing the va_list.
func NewVaListN(n int) (va_list uintptr) {
	return Xmalloc(nil, Tsize_t(8*n))
}

func SetEnviron(t *TLS, env []string) {
	__ccgo_environOnce.Do(func() {
		Xenviron = mustAllocStrings(env)
	})
}

func Dmesg(s string, args ...interface{}) {
	// nop
}

func Xalloca(tls *TLS, size Tsize_t) uintptr {
	return tls.alloca(size)
}

// struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg);
func X__cmsg_nxthdr(t *TLS, msgh, cmsg uintptr) uintptr {
	panic(todo(""))
}

func Cover() {
	runtime.Callers(2, coverPCs[:])
	Covered[coverPCs[0]] = struct{}{}
}

func CoverReport(w io.Writer) error {
	var a []string
	pcs := make([]uintptr, 1)
	for pc := range Covered {
		pcs[0] = pc
		frame, _ := runtime.CallersFrames(pcs).Next()
		a = append(a, fmt.Sprintf("%s:%07d:%s", filepath.Base(frame.File), frame.Line, frame.Func.Name()))
	}
	sort.Strings(a)
	_, err := fmt.Fprintf(w, "%s\n", strings.Join(a, "\n"))
	return err
}

func CoverC(s string) {
	CoveredC[s] = struct{}{}
}

func CoverCReport(w io.Writer) error {
	var a []string
	for k := range CoveredC {
		a = append(a, k)
	}
	sort.Strings(a)
	_, err := fmt.Fprintf(w, "%s\n", strings.Join(a, "\n"))
	return err
}

func X__ccgo_dmesg(t *TLS, fmt uintptr, va uintptr) {
	panic(todo(""))
}

func X__ccgo_getMutexType(tls *TLS, m uintptr) int32 { /* pthread_mutex_lock.c:3:5: */
	panic(todo(""))
}

func X__ccgo_in6addr_anyp(t *TLS) uintptr {
	panic(todo(""))
}

func X__ccgo_pthreadAttrGetDetachState(tls *TLS, a uintptr) int32 { /* pthread_attr_get.c:3:5: */
	panic(todo(""))
}

func X__ccgo_pthreadMutexattrGettype(tls *TLS, a uintptr) int32 { /* pthread_attr_get.c:93:5: */
	panic(todo(""))
}

// void sqlite3_log(int iErrCode, const char *zFormat, ...);
func X__ccgo_sqlite3_log(t *TLS, iErrCode int32, zFormat uintptr, args uintptr) {
	// nop
}

// unsigned __sync_add_and_fetch_uint32(*unsigned, unsigned)
func X__sync_add_and_fetch_uint32(t *TLS, p uintptr, v uint32) uint32 {
	return atomic.AddUint32((*uint32)(unsafe.Pointer(p)), v)
}

// unsigned __sync_sub_and_fetch_uint32(*unsigned, unsigned)
func X__sync_sub_and_fetch_uint32(t *TLS, p uintptr, v uint32) uint32 {
	return atomic.AddUint32((*uint32)(unsafe.Pointer(p)), -v)
}

var (
	randomData   = map[uintptr]*rand.Rand{}
	randomDataMu sync.Mutex
)

// The initstate_r() function is like initstate(3) except that it initializes
// the state in the object pointed to by buf, rather than initializing the
// global state  variable.   Before  calling this function, the buf.state field
// must be initialized to NULL.  The initstate_r() function records a pointer
// to the statebuf argument inside the structure pointed to by buf.  Thus,
// state‐ buf should not be deallocated so long as buf is still in use.  (So,
// statebuf should typically be allocated as a static variable, or allocated on
// the heap using malloc(3) or similar.)
//
// char *initstate_r(unsigned int seed, char *statebuf, size_t statelen, struct random_data *buf);
func Xinitstate_r(t *TLS, seed uint32, statebuf uintptr, statelen Tsize_t, buf uintptr) int32 {
	if buf == 0 {
		panic(todo(""))
	}

	randomDataMu.Lock()

	defer randomDataMu.Unlock()

	randomData[buf] = rand.New(rand.NewSource(int64(seed)))
	return 0
}

// int random_r(struct random_data *buf, int32_t *result);
func Xrandom_r(t *TLS, buf, result uintptr) int32 {
	randomDataMu.Lock()

	defer randomDataMu.Unlock()

	mr := randomData[buf]
	if RAND_MAX != math.MaxInt32 {
		panic(todo(""))
	}
	*(*int32)(unsafe.Pointer(result)) = mr.Int31()
	return 0
}

// void longjmp(jmp_buf env, int val);
func Xlongjmp(t *TLS, env uintptr, val int32) {
	panic(todo(""))
}

// void _longjmp(jmp_buf env, int val);
func X_longjmp(t *TLS, env uintptr, val int32) {
	panic(todo(""))
}

// int _obstack_begin (struct obstack *h, _OBSTACK_SIZE_T size, _OBSTACK_SIZE_T alignment,	void *(*chunkfun) (size_t),  void (*freefun) (void *))
func X_obstack_begin(t *TLS, obstack uintptr, size, alignment int32, chunkfun, freefun uintptr) int32 {
	panic(todo(""))
}

// extern void _obstack_newchunk(struct obstack *, int);
func X_obstack_newchunk(t *TLS, obstack uintptr, length int32) int32 {
	panic(todo(""))
}

// void obstack_free (struct obstack *h, void *obj)
func Xobstack_free(t *TLS, obstack, obj uintptr) {
	panic(todo(""))
}

// int obstack_vprintf (struct obstack *obstack, const char *template, va_list ap)
func Xobstack_vprintf(t *TLS, obstack, template, va uintptr) int32 {
	panic(todo(""))
}

// int _setjmp(jmp_buf env);
func X_setjmp(t *TLS, env uintptr) int32 {
	return 0 //TODO
}

// int setjmp(jmp_buf env);
func Xsetjmp(t *TLS, env uintptr) int32 {
	panic(todo(""))
}

// int backtrace(void **buffer, int size);
func Xbacktrace(t *TLS, buf uintptr, size int32) int32 {
	panic(todo(""))
}

// void backtrace_symbols_fd(void *const *buffer, int size, int fd);
func Xbacktrace_symbols_fd(t *TLS, buffer uintptr, size, fd int32) {
	panic(todo(""))
}

// int fts_close(FTS *ftsp);
func Xfts_close(t *TLS, ftsp uintptr) int32 {
	panic(todo(""))
}

// FTS *fts_open(char * const *path_argv, int options, int (*compar)(const FTSENT **, const FTSENT **));
func Xfts_open(t *TLS, path_argv uintptr, options int32, compar uintptr) uintptr {
	panic(todo(""))
}

// FTSENT *fts_read(FTS *ftsp);
func Xfts64_read(t *TLS, ftsp uintptr) uintptr {
	panic(todo(""))
}

// int fts_close(FTS *ftsp);
func Xfts64_close(t *TLS, ftsp uintptr) int32 {
	panic(todo(""))
}

// FTS *fts_open(char * const *path_argv, int options, int (*compar)(const FTSENT **, const FTSENT **));
func Xfts64_open(t *TLS, path_argv uintptr, options int32, compar uintptr) uintptr {
	panic(todo(""))
}

// FTSENT *fts_read(FTS *ftsp);
func Xfts_read(t *TLS, ftsp uintptr) uintptr {
	panic(todo(""))
}

// FILE *popen(const char *command, const char *type);
func Xpopen(t *TLS, command, type1 uintptr) uintptr {
	panic(todo(""))
}

// int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
func Xsysctlbyname(t *TLS, name, oldp, oldlenp, newp uintptr, newlen Tsize_t) int32 {
	oldlen := *(*Tsize_t)(unsafe.Pointer(oldlenp))
	switch GoString(name) {
	case "hw.ncpu":
		if oldlen != 4 {
			panic(todo(""))
		}

		*(*int32)(unsafe.Pointer(oldp)) = int32(runtime.GOMAXPROCS(-1))
		return 0
	default:
		t.setErrno(ENOENT)
		return -1
	}
}

// void uuid_copy(uuid_t dst, uuid_t src);
func Xuuid_copy(t *TLS, dst, src uintptr) {
	if __ccgo_strace {
		trc("t=%v src=%v, (%v:)", t, src, origin(2))
	}
	*(*uuid.Uuid_t)(unsafe.Pointer(dst)) = *(*uuid.Uuid_t)(unsafe.Pointer(src))
}

// int uuid_parse( char *in, uuid_t uu);
func Xuuid_parse(t *TLS, in uintptr, uu uintptr) int32 {
	if __ccgo_strace {
		trc("t=%v in=%v uu=%v, (%v:)", t, in, uu, origin(2))
	}
	r, err := guuid.Parse(GoString(in))
	if err != nil {
		return -1
	}

	copy((*RawMem)(unsafe.Pointer(uu))[:unsafe.Sizeof(uuid.Uuid_t{})], r[:])
	return 0
}

// void uuid_generate_random(uuid_t out);
func Xuuid_generate_random(t *TLS, out uintptr) {
	if __ccgo_strace {
		trc("t=%v out=%v, (%v:)", t, out, origin(2))
	}
	x := guuid.New()
	copy((*RawMem)(unsafe.Pointer(out))[:], x[:])
}

// void uuid_unparse(uuid_t uu, char *out);
func Xuuid_unparse(t *TLS, uu, out uintptr) {
	if __ccgo_strace {
		trc("t=%v out=%v, (%v:)", t, out, origin(2))
	}
	s := (*guuid.UUID)(unsafe.Pointer(uu)).String()
	copy((*RawMem)(unsafe.Pointer(out))[:], s)
	*(*byte)(unsafe.Pointer(out + uintptr(len(s)))) = 0
}

var Xzero_struct_address Taddress

// The env mirror helpers are called by the setenv family wrappers that
// generator.go appends to the generated file: a change made through the C
// environment functions is applied to the Go environment too, so that
// os.Getenv agrees with getenv. Changes made with os.Setenv are not visible
// to getenv; make them through the libc functions when C code must see them.

func envMirrorSet(name, value string) {
	os.Setenv(name, value)
}

func envMirrorUnset(name string) {
	os.Unsetenv(name)
}

// envMirrorPut applies a putenv string: "name=value" sets, "name" unsets.
func envMirrorPut(s string) {
	if x := strings.IndexByte(s, '='); x >= 0 {
		os.Setenv(s[:x], s[x+1:])
		return
	}

	os.Unsetenv(s)
}

func envMirrorClear() {
	os.Clearenv()
}
