<commit_before>#include"all_defines.hpp"

#include"processes.hpp"
#include"mutexes.hpp"
#include"executors.hpp"

void MailBox::insert(ValueHolderRef & message) {
	AppLock l(mtx);
	messages.insert(message);
}

bool MailBox::recv(Object::ref & res) {
	AppLock l(mtx);
	ValueHolderRef ref;
        messages.remove(ref);
	if (ref.empty()) {
		return false;
	} else {
		/*Save the received message's Semispace into
		  the heap's other spaces
		*/
		parent.heap().other_spaces.insert(ref);
		res = parent.heap().other_spaces.value();
		return true;
	}
}

bool MailBox::empty() {
	AppLock l(mtx);
	return messages.empty();
}

void MailBox::clear() {
	AppLock l(mtx);
	ValueHolderRef tmp;
	messages.swap(tmp);
}

/*
 * Process-level GC functions
 */
/*
Refer to doc/process-gc.txt and in particular src/workers.cpp
*/

bool Process::waiting_and_not_black(void) {
	AppLock l(mtx);
	return (stat == process_waiting) && !black;
}

bool Process::receive_message(ValueHolderRef& M, bool& is_waiting) {
	is_waiting = false;
	AppTryLock l(mtx);
	if(!l) return false; /*failed to lock, retry later*/
	if(stat == process_dead) return true; /*silently succeed*/
	mbox.insert(M);
	if(stat == process_waiting) {
		is_waiting = true;
		stat = process_running;
	}
	return true;
}

bool Process::anesthesize(void) {
	AppLock l(mtx);
	if(stat == process_waiting && !black) {
		stat = process_anesthesized;
		return true;
	} else {
		return false;
	}
}

bool Process::unanesthesize(void) {
	AppLock l(mtx);
	if (mbox.empty()) {
		stat = process_waiting;
		return false;
	} else {
		/*since the sender of the message can't send
		unless it gets the mutex (and we have the
		mutex), we expect mbox to be empty at this
		point
		*/
		stat = process_running;
		return true;
	}
}

void Process::kill(void) {
	stat = process_dead;
	mbox.clear();
	global_cache.clear();
	invalid_globals.clear();
	free_heap();
}
void Process::atomic_kill(void) {
	{AppLock l(mtx);
		stat = process_dead;
		mbox.clear();
	}
	/*used only when running anyway; since we're dead,
	no need to lock
	*/
	global_cache.clear();
	/*lock notification_mtx in case someone decides to
	notify us at this time
	*/
	{AppLock l(notification_mtx);
		invalid_globals.clear();
	}
	free_heap();
}

void Process::set_waiting() {
	AppLock l(mtx);
	stat = process_waiting;
}

Heap& Process::heap(void) {<commit_msg>src/processes.cpp: comment on race condition<commit_after>#include"all_defines.hpp"

#include"processes.hpp"
#include"mutexes.hpp"
#include"executors.hpp"

void MailBox::insert(ValueHolderRef & message) {
	AppLock l(mtx);
	messages.insert(message);
}

bool MailBox::recv(Object::ref & res) {
	AppLock l(mtx);
	ValueHolderRef ref;
        messages.remove(ref);
	if (ref.empty()) {
		return false;
	} else {
		/*Save the received message's Semispace into
		  the heap's other spaces
		*/
		parent.heap().other_spaces.insert(ref);
		res = parent.heap().other_spaces.value();
		return true;
	}
}

bool MailBox::empty() {
	AppLock l(mtx);
	return messages.empty();
}

void MailBox::clear() {
	AppLock l(mtx);
	ValueHolderRef tmp;
	messages.swap(tmp);
}

/*
 * Process-level GC functions
 */
/*
Refer to doc/process-gc.txt and in particular src/workers.cpp
*/

bool Process::waiting_and_not_black(void) {
	AppLock l(mtx);
	return (stat == process_waiting) && !black;
}

bool Process::receive_message(ValueHolderRef& M, bool& is_waiting) {
	is_waiting = false;
	AppTryLock l(mtx);
	if(!l) return false; /*failed to lock, retry later*/
	if(stat == process_dead) return true; /*silently succeed*/
	mbox.insert(M);
	if(stat == process_waiting) {
		is_waiting = true;
		stat = process_running;
	}
	return true;
}

bool Process::anesthesize(void) {
	AppLock l(mtx);
	if(stat == process_waiting && !black) {
		stat = process_anesthesized;
		return true;
	} else {
		return false;
	}
}

bool Process::unanesthesize(void) {
	AppLock l(mtx);
	if (mbox.empty()) {
		stat = process_waiting;
		return false;
	} else {
		/*since the sender of the message can't send
		unless it gets the mutex (and we have the
		mutex), we expect mbox to be empty at this
		point
		*/
		stat = process_running;
		return true;
	}
}

void Process::kill(void) {
	stat = process_dead;
	mbox.clear();
	global_cache.clear();
	invalid_globals.clear();
	free_heap();
}
void Process::atomic_kill(void) {
	{AppLock l(mtx);
		stat = process_dead;
		mbox.clear();
	}
	/*used only when running anyway; since we're dead,
	no need to lock
	*/
	global_cache.clear();
	/*lock notification_mtx in case someone decides to
	notify us at this time
	*/
	{AppLock l(notification_mtx);
		invalid_globals.clear();
	}
	free_heap();
}

void Process::set_waiting() {
/*
NOTE!  This is not atomic enough!
The following race condition can occur:
  S:  (==> R msg)
  R:  (<== msg (do-something msg))

1.  R checks its mailbox.  It finds it empty.
2.  S sends message to R.  It inserts the new message
    into the mailbox.  It detects that R is currently
    process_running, so it does not schedule the
    message sending.
3.  R changes its state to process_waiting and returns
    process_waiting, causing the worker to drop it.

This means that R has *received* a message, but is
still in a "waiting" state.

Both stat and the mailbox should be protected by a
*single* lock.

--almkglor
*/
	AppLock l(mtx);
	stat = process_waiting;
}

Heap& Process::heap(void) {
{'fraction_non_alphanumeric': 0.13237221494102228, 'fraction_numerical': 0.0005616925669350309, 'mean_word_length': 4.12176414189837, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, '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': '5897313', 'n_tokens_mistral': 1991, 'n_tokens_neox': 1919, 'n_words': 523}