2022-03-07 17:21:13 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) Atmosphère-NX
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms and conditions of the GNU General Public License,
|
|
|
|
* version 2, as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2022-03-06 22:13:10 +00:00
|
|
|
#include <stratosphere.hpp>
|
|
|
|
|
|
|
|
namespace ams {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
struct InterThreadSync {
|
|
|
|
util::Atomic<int> reader_state;
|
|
|
|
util::Atomic<int> writer_state;
|
|
|
|
os::EventType writer_ready_event;
|
|
|
|
os::EventType reader_ready_event;
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
os::SystemEventType system_event_as_manual_clear_event;
|
|
|
|
os::SystemEventType system_event_as_manual_clear_interprocess_event;
|
|
|
|
os::SystemEventType system_event_as_auto_clear_event;
|
|
|
|
os::SystemEventType system_event_as_auto_clear_interprocess_event;
|
|
|
|
};
|
|
|
|
os::SystemEventType system_events[4];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
bool IsManualClearEventIndex(size_t i) {
|
|
|
|
return i == 0 || i == 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
alignas(os::MemoryPageSize) constinit u8 g_writer_thread_stack[16_KB];
|
|
|
|
alignas(os::MemoryPageSize) constinit u8 g_reader_thread_stack[16_KB];
|
|
|
|
|
|
|
|
void TestWriterThread(void *arg) {
|
|
|
|
/* Get the synchronization arguments. */
|
|
|
|
auto &sync = *static_cast<InterThreadSync *>(arg);
|
|
|
|
AMS_UNUSED(sync);
|
|
|
|
|
|
|
|
/* Wait for reader to be ready. */
|
|
|
|
os::WaitEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.reader_state == 1);
|
|
|
|
|
|
|
|
/* Verify that all events can be signaled. */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Set the event for this go. */
|
|
|
|
os::SignalSystemEvent(sync.system_events + i);
|
|
|
|
|
|
|
|
sync.writer_state = 1;
|
|
|
|
os::SignalEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
|
|
|
|
/* Wait for the reader to finish. */
|
|
|
|
os::WaitEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.reader_state == 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that all events can be signaled (for TimedWait 0). */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Set the event for this go. */
|
|
|
|
os::SignalSystemEvent(sync.system_events + i);
|
|
|
|
|
|
|
|
sync.writer_state = 2;
|
|
|
|
os::SignalEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
|
|
|
|
/* Wait for the reader to finish. */
|
|
|
|
os::WaitEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.reader_state == 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that all events can be signaled (for TimedWait 2). */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Set the event for this go. */
|
|
|
|
os::SignalSystemEvent(sync.system_events + i);
|
|
|
|
|
|
|
|
sync.writer_state = 3;
|
|
|
|
os::SignalEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
|
|
|
|
/* Wait for the reader to finish. */
|
|
|
|
os::WaitEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.reader_state == 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that all events can be signaled (for True Wait). */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Set the event for this go. */
|
|
|
|
os::SignalSystemEvent(sync.system_events + i);
|
|
|
|
|
|
|
|
sync.writer_state = 4;
|
|
|
|
os::SignalEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
|
|
|
|
/* Wait for the reader to finish. */
|
|
|
|
os::WaitEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.reader_state == 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that all events can be signaled (TryWaitAny). */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Set the event for this go. */
|
|
|
|
os::SignalSystemEvent(sync.system_events + i);
|
|
|
|
|
|
|
|
sync.writer_state = 5;
|
|
|
|
os::SignalEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
|
|
|
|
/* Wait for the reader to finish. */
|
|
|
|
os::WaitEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.reader_state == 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that all events can be signaled (TimedWaitAny 0). */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Set the event for this go. */
|
|
|
|
os::SignalSystemEvent(sync.system_events + i);
|
|
|
|
|
|
|
|
sync.writer_state = 6;
|
|
|
|
os::SignalEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
|
|
|
|
/* Wait for the reader to finish. */
|
|
|
|
os::WaitEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.reader_state == 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that all events can be signaled (TimedWaitAny 2). */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Set the event for this go. */
|
|
|
|
os::SignalSystemEvent(sync.system_events + i);
|
|
|
|
|
|
|
|
sync.writer_state = 7;
|
|
|
|
os::SignalEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
|
|
|
|
/* Wait for the reader to finish. */
|
|
|
|
os::WaitEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.reader_state == 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that all events can be signaled (TrueWaitAny). */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Set the event for this go. */
|
|
|
|
os::SignalSystemEvent(sync.system_events + i);
|
|
|
|
|
|
|
|
sync.writer_state = 8;
|
|
|
|
os::SignalEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
|
|
|
|
/* Wait for the reader to finish. */
|
|
|
|
os::WaitEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.reader_state == 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that reader can receive without explicit sync. */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Set the event for this go. */
|
|
|
|
os::SignalSystemEvent(sync.system_events + i);
|
|
|
|
|
|
|
|
sync.writer_state = 9;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wait for the reader to finish. */
|
|
|
|
os::WaitEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.reader_state == 9);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestReaderThread(void *arg) {
|
|
|
|
/* Get the synchronization arguments. */
|
|
|
|
auto &sync = *static_cast<InterThreadSync *>(arg);
|
|
|
|
AMS_UNUSED(sync);
|
|
|
|
|
|
|
|
/* Set up multi-wait objects. */
|
|
|
|
os::MultiWaitType mw;
|
|
|
|
os::MultiWaitHolderType holders[util::size(sync.system_events)];
|
|
|
|
os::InitializeMultiWait(std::addressof(mw));
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
os::InitializeMultiWaitHolder(holders + i, sync.system_events + i);
|
|
|
|
os::LinkMultiWaitHolder(std::addressof(mw), holders + i);
|
|
|
|
}
|
|
|
|
ON_SCOPE_EXIT {
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
os::UnlinkMultiWaitHolder(holders + i);
|
|
|
|
os::FinalizeMultiWaitHolder(holders + i);
|
|
|
|
}
|
|
|
|
os::FinalizeMultiWait(std::addressof(mw));
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Sanity check: all events are non-signaled. */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + i) == false);
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitSystemEvent(sync.system_events + i, TimeSpan::FromNanoSeconds(0)) == false);
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitSystemEvent(sync.system_events + i, TimeSpan::FromMilliSeconds(2)) == false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sanity check that wait any does the right thing when nothing is signaled. */
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitAny(std::addressof(mw)) == nullptr);
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitAny(std::addressof(mw), TimeSpan::FromNanoSeconds(0)) == nullptr);
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitAny(std::addressof(mw), TimeSpan::FromNanoSeconds(2)) == nullptr);
|
|
|
|
|
|
|
|
/* Let writer know that we're ready. */
|
|
|
|
sync.reader_state = 1;
|
|
|
|
os::SignalEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
|
|
|
|
/* Verify that we can receive signal on each event. */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Wait for writer to do the relevant work */
|
|
|
|
os::WaitEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.writer_state == 1);
|
|
|
|
|
|
|
|
/* Test all events. */
|
|
|
|
for (size_t n = 0; n < util::size(sync.system_events); ++n) {
|
|
|
|
if (i == n) {
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == true);
|
|
|
|
if (IsManualClearEventIndex(n)) {
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == true);
|
|
|
|
os::ClearSystemEvent(sync.system_events + n);
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == false);
|
|
|
|
} else {
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == false);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Let writer know we're done. */
|
|
|
|
sync.reader_state = 1;
|
|
|
|
os::SignalEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that we can receive signal on each event (Timed Wait 0). */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Wait for writer to do the relevant work */
|
|
|
|
os::WaitEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.writer_state == 2);
|
|
|
|
|
|
|
|
/* Test all events. */
|
|
|
|
for (size_t n = 0; n < util::size(sync.system_events); ++n) {
|
|
|
|
if (i == n) {
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitSystemEvent(sync.system_events + n, TimeSpan::FromMilliSeconds(0)) == true);
|
|
|
|
if (IsManualClearEventIndex(n)) {
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitSystemEvent(sync.system_events + n, TimeSpan::FromMilliSeconds(0)) == true);
|
|
|
|
os::ClearSystemEvent(sync.system_events + n);
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitSystemEvent(sync.system_events + n, TimeSpan::FromMilliSeconds(0)) == false);
|
|
|
|
} else {
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitSystemEvent(sync.system_events + n, TimeSpan::FromMilliSeconds(0)) == false);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitSystemEvent(sync.system_events + n, TimeSpan::FromMilliSeconds(0)) == false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Let writer know we're done. */
|
|
|
|
sync.reader_state = 2;
|
|
|
|
os::SignalEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that we can receive signal on each event (Timed Wait 2). */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Wait for writer to do the relevant work */
|
|
|
|
os::WaitEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.writer_state == 3);
|
|
|
|
|
|
|
|
/* Test all events. */
|
|
|
|
for (size_t n = 0; n < util::size(sync.system_events); ++n) {
|
|
|
|
if (i == n) {
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitSystemEvent(sync.system_events + n, TimeSpan::FromMilliSeconds(2)) == true);
|
|
|
|
if (IsManualClearEventIndex(n)) {
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitSystemEvent(sync.system_events + n, TimeSpan::FromMilliSeconds(2)) == true);
|
|
|
|
os::ClearSystemEvent(sync.system_events + n);
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitSystemEvent(sync.system_events + n, TimeSpan::FromMilliSeconds(2)) == false);
|
|
|
|
} else {
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitSystemEvent(sync.system_events + n, TimeSpan::FromMilliSeconds(2)) == false);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
AMS_ABORT_UNLESS(os::TimedWaitSystemEvent(sync.system_events + n, TimeSpan::FromMilliSeconds(2)) == false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Let writer know we're done. */
|
|
|
|
sync.reader_state = 3;
|
|
|
|
os::SignalEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that we can receive signal on each event. */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Wait for writer to do the relevant work */
|
|
|
|
os::WaitEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.writer_state == 4);
|
|
|
|
|
|
|
|
/* Test all events. */
|
|
|
|
for (size_t n = 0; n < util::size(sync.system_events); ++n) {
|
|
|
|
if (i == n) {
|
|
|
|
os::WaitSystemEvent(sync.system_events + n);
|
|
|
|
if (IsManualClearEventIndex(n)) {
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == true);
|
|
|
|
os::WaitSystemEvent(sync.system_events + n);
|
|
|
|
os::ClearSystemEvent(sync.system_events + n);
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == false);
|
|
|
|
} else {
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == false);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Let writer know we're done. */
|
|
|
|
sync.reader_state = 4;
|
|
|
|
os::SignalEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that we can receive signal on each event (TryWaitAny) */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Wait for writer to do the relevant work */
|
|
|
|
os::WaitEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.writer_state == 5);
|
|
|
|
|
|
|
|
/* Get the signaled holder. */
|
|
|
|
auto *signaled = os::TryWaitAny(std::addressof(mw));
|
|
|
|
AMS_ABORT_UNLESS(signaled == holders + i);
|
|
|
|
|
|
|
|
/* Test all events. */
|
|
|
|
for (size_t n = 0; n < util::size(sync.system_events); ++n) {
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == (i == n));
|
|
|
|
os::ClearSystemEvent(sync.system_events + n);
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Let writer know we're done. */
|
|
|
|
sync.reader_state = 5;
|
|
|
|
os::SignalEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that we can receive signal on each event (TimedWaitAny 0) */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Wait for writer to do the relevant work */
|
|
|
|
os::WaitEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.writer_state == 6);
|
|
|
|
|
|
|
|
/* Get the signaled holder. */
|
|
|
|
auto *signaled = os::TimedWaitAny(std::addressof(mw), TimeSpan::FromMilliSeconds(0));
|
|
|
|
AMS_ABORT_UNLESS(signaled == holders + i);
|
|
|
|
|
|
|
|
/* Test all events. */
|
|
|
|
for (size_t n = 0; n < util::size(sync.system_events); ++n) {
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == (i == n));
|
|
|
|
os::ClearSystemEvent(sync.system_events + n);
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Let writer know we're done. */
|
|
|
|
sync.reader_state = 6;
|
|
|
|
os::SignalEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that we can receive signal on each event (TimedWaitAny 2) */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Wait for writer to do the relevant work */
|
|
|
|
os::WaitEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.writer_state == 7);
|
|
|
|
|
|
|
|
/* Get the signaled holder. */
|
|
|
|
auto *signaled = os::TimedWaitAny(std::addressof(mw), TimeSpan::FromMilliSeconds(2));
|
|
|
|
AMS_ABORT_UNLESS(signaled == holders + i);
|
|
|
|
|
|
|
|
/* Test all events. */
|
|
|
|
for (size_t n = 0; n < util::size(sync.system_events); ++n) {
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == (i == n));
|
|
|
|
os::ClearSystemEvent(sync.system_events + n);
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Let writer know we're done. */
|
|
|
|
sync.reader_state = 7;
|
|
|
|
os::SignalEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that we can receive signal on each event (True WaitAny) */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
/* Wait for writer to do the relevant work */
|
|
|
|
os::WaitEvent(std::addressof(sync.writer_ready_event));
|
|
|
|
AMS_ABORT_UNLESS(sync.writer_state == 8);
|
|
|
|
|
|
|
|
/* Get the signaled holder. */
|
|
|
|
auto *signaled = os::WaitAny(std::addressof(mw));
|
|
|
|
AMS_ABORT_UNLESS(signaled == holders + i);
|
|
|
|
|
|
|
|
/* Test all events. */
|
|
|
|
for (size_t n = 0; n < util::size(sync.system_events); ++n) {
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == (i == n));
|
|
|
|
os::ClearSystemEvent(sync.system_events + n);
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Let writer know we're done. */
|
|
|
|
sync.reader_state = 8;
|
|
|
|
os::SignalEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that we can receive wait-any signals without sync. */
|
|
|
|
for (size_t i = 0; i < util::size(sync.system_events); ++i) {
|
|
|
|
auto *signaled = os::WaitAny(std::addressof(mw));
|
|
|
|
AMS_ABORT_UNLESS(signaled != nullptr);
|
|
|
|
const size_t n = signaled - holders;
|
|
|
|
AMS_ABORT_UNLESS(n < util::size(sync.system_events));
|
|
|
|
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == true);
|
|
|
|
os::ClearSystemEvent(sync.system_events + n);
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitSystemEvent(sync.system_events + n) == false);
|
|
|
|
}
|
|
|
|
|
|
|
|
AMS_ABORT_UNLESS(os::TryWaitAny(std::addressof(mw)) == nullptr);
|
|
|
|
|
|
|
|
/* Let writer know we're done. */
|
|
|
|
sync.reader_state = 9;
|
|
|
|
os::SignalEvent(std::addressof(sync.reader_ready_event));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Main() {
|
|
|
|
printf("Doing OS Event tests!\n");
|
|
|
|
{
|
|
|
|
/* Create the synchronization state. */
|
|
|
|
InterThreadSync sync_state;
|
|
|
|
sync_state.reader_state = 0;
|
|
|
|
sync_state.writer_state = 0;
|
|
|
|
os::InitializeEvent(std::addressof(sync_state.writer_ready_event), false, os::EventClearMode_AutoClear);
|
|
|
|
os::InitializeEvent(std::addressof(sync_state.reader_ready_event), false, os::EventClearMode_AutoClear);
|
|
|
|
|
|
|
|
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(sync_state.system_event_as_manual_clear_event), os::EventClearMode_ManualClear, false));
|
|
|
|
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(sync_state.system_event_as_manual_clear_interprocess_event), os::EventClearMode_ManualClear, true));
|
|
|
|
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(sync_state.system_event_as_auto_clear_event), os::EventClearMode_AutoClear, false));
|
|
|
|
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(sync_state.system_event_as_auto_clear_interprocess_event), os::EventClearMode_AutoClear, true));
|
|
|
|
|
|
|
|
/* Ensure we clean up the sync-state when done. */
|
|
|
|
ON_SCOPE_EXIT {
|
|
|
|
os::FinalizeEvent(std::addressof(sync_state.writer_ready_event));
|
|
|
|
os::FinalizeEvent(std::addressof(sync_state.reader_ready_event));
|
|
|
|
|
|
|
|
os::DestroySystemEvent(std::addressof(sync_state.system_event_as_manual_clear_event));
|
|
|
|
os::DestroySystemEvent(std::addressof(sync_state.system_event_as_manual_clear_interprocess_event));
|
|
|
|
os::DestroySystemEvent(std::addressof(sync_state.system_event_as_auto_clear_event));
|
|
|
|
os::DestroySystemEvent(std::addressof(sync_state.system_event_as_auto_clear_interprocess_event));
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Create the threads. */
|
|
|
|
os::ThreadType reader_thread, writer_thread;
|
|
|
|
R_ABORT_UNLESS(os::CreateThread(std::addressof(reader_thread), TestReaderThread, std::addressof(sync_state), g_reader_thread_stack, sizeof(g_reader_thread_stack), os::DefaultThreadPriority));
|
|
|
|
R_ABORT_UNLESS(os::CreateThread(std::addressof(writer_thread), TestWriterThread, std::addressof(sync_state), g_writer_thread_stack, sizeof(g_writer_thread_stack), os::DefaultThreadPriority));
|
|
|
|
os::SetThreadNamePointer(std::addressof(reader_thread), "ReaderThread");
|
|
|
|
os::SetThreadNamePointer(std::addressof(writer_thread), "WriterThread");
|
|
|
|
|
|
|
|
/* Start the threads. */
|
|
|
|
os::StartThread(std::addressof(reader_thread));
|
|
|
|
os::StartThread(std::addressof(writer_thread));
|
|
|
|
|
|
|
|
/* Wait for the threads to complete. */
|
|
|
|
os::WaitThread(std::addressof(reader_thread));
|
|
|
|
os::WaitThread(std::addressof(writer_thread));
|
|
|
|
|
|
|
|
/* Destroy the threads. */
|
|
|
|
os::WaitThread(std::addressof(reader_thread));
|
|
|
|
os::WaitThread(std::addressof(writer_thread));
|
|
|
|
}
|
|
|
|
printf("All tests completed!\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|