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

#include "runtime.h"
#include "defs.h"
#include "os.h"

static void
unimplemented(int8 *name)
{
	prints(name);
	prints(" not implemented\n");
	*(int32*)1231 = 1231;
}

// Thread-safe allocation of a semaphore.
// Psema points at a kernel semaphore key.
// It starts out zero, meaning no semaphore.
// Fill it in, being careful of others calling initsema
// simultaneously.
static void
initsema(uint32 *psema)
{
	uint32 sema;

	if(*psema != 0)	// already have one
		return;

	sema = mach_semcreate();
	if(!cas(psema, 0, sema)){
		// Someone else filled it in.  Use theirs.
		mach_semdestroy(sema);
		return;
	}
}


// Blocking locks.

// Implement Locks, using semaphores.
// l->key is the number of threads who want the lock.
// In a race, one thread increments l->key from 0 to 1
// and the others increment it from >0 to >1.  The thread
// who does the 0->1 increment gets the lock, and the
// others wait on the semaphore.  When the 0->1 thread
// releases the lock by decrementing l->key, l->key will
// be >0, so it will increment the semaphore to wake up
// one of the others.  This is the same algorithm used
// in Plan 9's user-level locks.
//
// Note that semaphores are never destroyed (the kernel
// will clean up when the process exits).  We assume for now
// that Locks are only used for long-lived structures like M and G.

void
lock(Lock *l)
{
	if(m->locks < 0)
		throw("lock count");
	m->locks++;

	// Allocate semaphore if needed.
	if(l->sema == 0)
		initsema(&l->sema);

	if(xadd(&l->key, 1) > 1)	// someone else has it; wait
		mach_semacquire(l->sema);
}

void
unlock(Lock *l)
{
	m->locks--;
	if(m->locks < 0)
		throw("lock count");

	if(xadd(&l->key, -1) > 0)	// someone else is waiting
		mach_semrelease(l->sema);
}


// User-level semaphore implementation:
// try to do the operations in user space on u,
// but when it's time to block, fall back on the kernel semaphore k.
// This is the same algorithm used in Plan 9.
void
usemacquire(Usema *s)
{
	if((int32)xadd(&s->u, -1) < 0)
		mach_semacquire(s->k);
}

void
usemrelease(Usema *s)
{
	if((int32)xadd(&s->u, 1) <= 0)
		mach_semrelease(s->k);
}


// Event notifications.
void
noteclear(Note *n)
{
	n->wakeup = 0;
}

void
notesleep(Note *n)
{
	if(n->sema.k == 0)
		initsema(&n->sema.k);
	while(!n->wakeup)
		usemacquire(&n->sema);
}

void
notewakeup(Note *n)
{
	if(n->sema.k == 0)
		initsema(&n->sema.k);
	n->wakeup = 1;
	usemrelease(&n->sema);
}


// BSD interface for threading.
void
osinit(void)
{
	// Register our thread-creation callback (see {amd64,386}/sys.s)
	// but only if we're not using cgo.  If we are using cgo we need
	// to let the C pthread libary install its own thread-creation callback.<commit_msg>runtime: wait to allocate mach semaphores backing Locks until needed<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include "runtime.h"
#include "defs.h"
#include "os.h"

static void
unimplemented(int8 *name)
{
	prints(name);
	prints(" not implemented\n");
	*(int32*)1231 = 1231;
}

// Thread-safe allocation of a semaphore.
// Psema points at a kernel semaphore key.
// It starts out zero, meaning no semaphore.
// Fill it in, being careful of others calling initsema
// simultaneously.
static void
initsema(uint32 *psema)
{
	uint32 sema;

	if(*psema != 0)	// already have one
		return;

	sema = mach_semcreate();
	if(!cas(psema, 0, sema)){
		// Someone else filled it in.  Use theirs.
		mach_semdestroy(sema);
		return;
	}
}


// Blocking locks.

// Implement Locks, using semaphores.
// l->key is the number of threads who want the lock.
// In a race, one thread increments l->key from 0 to 1
// and the others increment it from >0 to >1.  The thread
// who does the 0->1 increment gets the lock, and the
// others wait on the semaphore.  When the 0->1 thread
// releases the lock by decrementing l->key, l->key will
// be >0, so it will increment the semaphore to wake up
// one of the others.  This is the same algorithm used
// in Plan 9's user-level locks.
//
// Note that semaphores are never destroyed (the kernel
// will clean up when the process exits).  We assume for now
// that Locks are only used for long-lived structures like M and G.

void
lock(Lock *l)
{
	if(m->locks < 0)
		throw("lock count");
	m->locks++;

	if(xadd(&l->key, 1) > 1) {	// someone else has it; wait
		// Allocate semaphore if needed.
		if(l->sema == 0)
			initsema(&l->sema);
		mach_semacquire(l->sema);
	}
}

void
unlock(Lock *l)
{
	m->locks--;
	if(m->locks < 0)
		throw("lock count");

	if(xadd(&l->key, -1) > 0) {	// someone else is waiting
		// Allocate semaphore if needed.
		if(l->sema == 0)
			initsema(&l->sema);
		mach_semrelease(l->sema);
	}
}


// User-level semaphore implementation:
// try to do the operations in user space on u,
// but when it's time to block, fall back on the kernel semaphore k.
// This is the same algorithm used in Plan 9.
void
usemacquire(Usema *s)
{
	if((int32)xadd(&s->u, -1) < 0) {
		if(s->k == 0)
			initsema(&s->k);
		mach_semacquire(s->k);
	}
}

void
usemrelease(Usema *s)
{
	if((int32)xadd(&s->u, 1) <= 0) {
		if(s->k == 0)
			initsema(&s->k);
		mach_semrelease(s->k);
	}
}


// Event notifications.
void
noteclear(Note *n)
{
	n->wakeup = 0;
}

void
notesleep(Note *n)
{
	while(!n->wakeup)
		usemacquire(&n->sema);
}

void
notewakeup(Note *n)
{
	n->wakeup = 1;
	usemrelease(&n->sema);
}


// BSD interface for threading.
void
osinit(void)
{
	// Register our thread-creation callback (see {amd64,386}/sys.s)
	// but only if we're not using cgo.  If we are using cgo we need
	// to let the C pthread libary install its own thread-creation callback.
{'fraction_non_alphanumeric': 0.14105621805792162, 'fraction_numerical': 0.019250425894378195, 'mean_word_length': 3.226781857451404, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 73, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '103009', 'n_tokens_mistral': 2314, 'n_tokens_neox': 2163, 'n_words': 757}