blob: d85b889899efda6728ac18d6f1a745b74f5243d3 [file] [log] [blame]
/*
* Copyright (c) 2011 The Native Client Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
// ConditionVariableEvents provides a doubly-link-list of events for use
// exclusively by the ConditionVariable class.
// This custom container was crafted because no simple combination of STL
// classes appeared to support the functionality required. The specific
// unusual requirement for a linked-list-class is support for the Extract()
// method, which can remove an element from a list, potentially for insertion
// into a second list. Most critically, the Extract() method is idempotent,
// turning the indicated element into an extracted singleton whether it was
// contained in a list or not. This functionality allows one (or more) of
// threads to do the extraction. The iterator that identifies this extractable
// element (in this case, a pointer to the list element) can be used after
// arbitrary manipulation of the (possibly) enclosing list container. In
// general, STL containers do not provide iterators that can be used across
// modifications (insertions/extractions) of the enclosing containers, and
// certainly don't provide iterators that can be used if the identified
// element is *deleted* (removed) from the container.
// It is possible to use multiple redundant containers, such as an STL list,
// and an STL map, to achieve similar container semantics. This container has
// only O(1) methods, while the corresponding (multiple) STL container approach
// would have more complex O(log(N)) methods (yeah... N isn't that large).
// Multiple containers also makes correctness more difficult to assert, as
// data is redundantly stored and maintained, which is generally evil.
#ifndef NATIVE_CLIENT_SRC_TRUSTED_PLATFORM_WIN_CONDITION_VARIABLE_EVENTS_H_
#define NATIVE_CLIENT_SRC_TRUSTED_PLATFORM_WIN_CONDITION_VARIABLE_EVENTS_H_
#include "native_client/src/shared/platform/win/lock.h"
#include "native_client/src/shared/platform/nacl_log.h"
#include "native_client/src/shared/platform/nacl_check.h"
namespace NaCl {
class ConditionVariable;
// Define elements that are used in a circular linked list.
// The list container is an element with zero as handle_ value.
// The actual list elements will have a non-zero HANDLE as their handle_.
// All access to methods MUST be done under protection of a lock so that links
// can be validated (and not asynchronously changing) during the method calls.
class ConditionVariableEvent {
private:
friend class ConditionVariable;
HANDLE handle_;
ConditionVariableEvent* next_; // Doubly linked list.
ConditionVariableEvent* prev_;
// Default constructor with no arguments creates a list container.
explicit ConditionVariableEvent(bool is_list_element = false) {
if (is_list_element) {
handle_ = CreateEvent(NULL, false, false, NULL);
// DCHECK(0 != handle_); // InitCheck will validate in production.
} else {
handle_ = 0;
}
next_ = prev_ = this; // Self referencing circular.
}
~ConditionVariableEvent() {
// DCHECK(IsSingleton());
if (0 != handle_) {
if (0 == CloseHandle(handle_)) {
NaClLog(LOG_ERROR, "CloseHandle returned 0"
"in ~ConditionVariableEvent()");
}
}
}
// Methods for use on lists.
bool IsEmpty() {
// DCHECK(ValidateAsList());
return IsSingleton();
}
void PushBack(ConditionVariableEvent* other) {
// DCHECK(ValidateAsList());
// DCHECK(other->ValidateAsItem());
// DCHECK(other->IsSingleton());
// Prepare other for insertion.
other->prev_ = prev_;
other->next_ = this;
// Cut into list.
prev_->next_ = other;
prev_ = other;
// DCHECK(ValidateAsDistinct(other));
}
ConditionVariableEvent* PopFront() {
// DCHECK(ValidateAsList());
// DCHECK(!IsSingleton());
return next_->Extract();
}
ConditionVariableEvent* PopBack() {
// DCHECK(ValidateAsList());
// DCHECK(!IsSingleton());
return prev_->Extract();
}
// Methods for use on list elements.
// Accessor method.
HANDLE handle() {
// DCHECK(ValidateAsItem());
return handle_;
}
// Pull an element from a list (if it's in one).
ConditionVariableEvent* Extract() {
// DCHECK(ValidateAsItem());
if (!IsSingleton()) {
// Stitch neighbors together.
next_->prev_ = prev_;
prev_->next_ = next_;
// Make extractee into a singleton.
prev_ = next_ = this;
}
// DCHECK(IsSingleton());
return this;
}
// Method for use on a list element or on a list.
bool IsSingleton() {
// DCHECK(ValidateLinks());
return next_ == this;
}
// Provide pre/post conditions to validate correct manipulations.
bool ValidateAsDistinct(ConditionVariableEvent* other) {
return ValidateLinks() && other->ValidateLinks() && (this != other);
}
bool ValidateAsItem() {
return (0 != handle_) && ValidateLinks();
}
bool ValidateAsList() {
return (0 == handle_) && ValidateLinks();
}
bool ValidateLinks() {
// Make sure our neighbor's link to us.
return (next_->prev_ == this) && (prev_->next_ == this);
}
NACL_DISALLOW_COPY_AND_ASSIGN(ConditionVariableEvent);
};
} // namespace NaCl
#endif // NATIVE_CLIENT_SRC_TRUSTED_PLATFORM_WIN_CONDITION_VARIABLE_EVENTS_H_