diff options
| author | bunnei <bunneidev@gmail.com> | 2015-01-08 22:38:33 -0500 | 
|---|---|---|
| committer | bunnei <bunneidev@gmail.com> | 2015-01-08 22:38:33 -0500 | 
| commit | d46f6500363024ac58cc23ba706e26d531a6076a (patch) | |
| tree | b5818b8b26092f425dccff628517f51fde47aaed /src/core/hle/kernel | |
| parent | 97cfdd16e637edceb08c81f446964bb9f52330b9 (diff) | |
| parent | 07044651ef2644451dc4f78045856ad078cb69fe (diff) | |
Merge pull request #255 from Subv/cbranch_3
Implemented timers
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/timer.cpp | 142 | ||||
| -rw-r--r-- | src/core/hle/kernel/timer.h | 47 | 
5 files changed, 194 insertions, 1 deletions
| diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index ae2c11a1c..391e833c0 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -9,6 +9,7 @@  #include "core/core.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/timer.h"  namespace Kernel { @@ -105,12 +106,13 @@ void HandleTable::Clear() {  /// Initialize the kernel  void Init() {      Kernel::ThreadingInit(); +    Kernel::TimersInit();  }  /// Shutdown the kernel  void Shutdown() {      Kernel::ThreadingShutdown(); - +    Kernel::TimersShutdown();      g_handle_table.Clear(); // Free all kernel objects  } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 7f86fd07d..3e381d776 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -39,6 +39,7 @@ enum class HandleType : u32 {      Process         = 8,      AddressArbiter  = 9,      Semaphore       = 10, +    Timer           = 11  };  enum { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index e6961e279..58bd85ac6 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -43,6 +43,7 @@ enum WaitType {      WAITTYPE_MUTEX,      WAITTYPE_SYNCH,      WAITTYPE_ARB, +    WAITTYPE_TIMER,  };  namespace Kernel { diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp new file mode 100644 index 000000000..7ac669e31 --- /dev/null +++ b/src/core/hle/kernel/timer.cpp @@ -0,0 +1,142 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <set> + +#include "common/common.h" + +#include "core/core_timing.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/timer.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +class Timer : public Object { +public: +    std::string GetTypeName() const override { return "Timer"; } +    std::string GetName() const override { return name; } + +    static const HandleType HANDLE_TYPE = HandleType::Timer; +    HandleType GetHandleType() const override { return HANDLE_TYPE; } + +    ResetType reset_type;                   ///< The ResetType of this timer + +    bool signaled;                          ///< Whether the timer has been signaled or not +    std::set<Handle> waiting_threads;       ///< Threads that are waiting for the timer +    std::string name;                       ///< Name of timer (optional) + +    u64 initial_delay;                      ///< The delay until the timer fires for the first time +    u64 interval_delay;                     ///< The delay until the timer fires after the first time + +    ResultVal<bool> WaitSynchronization() override { +        bool wait = !signaled; +        if (wait) { +            waiting_threads.insert(GetCurrentThreadHandle()); +            Kernel::WaitCurrentThread(WAITTYPE_TIMER, GetHandle()); +        } +        return MakeResult<bool>(wait); +    } +}; + +/** + * Creates a timer. + * @param handle Reference to handle for the newly created timer + * @param reset_type ResetType describing how to create timer + * @param name Optional name of timer + * @return Newly created Timer object + */ +Timer* CreateTimer(Handle& handle, const ResetType reset_type, const std::string& name) { +    Timer* timer = new Timer; + +    handle = Kernel::g_handle_table.Create(timer).ValueOr(INVALID_HANDLE); + +    timer->reset_type = reset_type; +    timer->signaled = false; +    timer->name = name; +    timer->initial_delay = 0; +    timer->interval_delay = 0; +    return timer; +} + +ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name) { +    CreateTimer(*handle, reset_type, name); +    return RESULT_SUCCESS; +} + +ResultCode ClearTimer(Handle handle) { +    Timer* timer = Kernel::g_handle_table.Get<Timer>(handle); +     +    if (timer == nullptr) +        return InvalidHandle(ErrorModule::Kernel); + +    timer->signaled = false; +    return RESULT_SUCCESS; +} + +/// The event type of the generic timer callback event +static int TimerCallbackEventType = -1; + +/// The timer callback event, called when a timer is fired +static void TimerCallback(u64 timer_handle, int cycles_late) { +    Timer* timer = Kernel::g_handle_table.Get<Timer>(timer_handle); + +    if (timer == nullptr) { +        LOG_CRITICAL(Kernel, "Callback fired for invalid timer %u", timer_handle); +        return; +    } + +    LOG_TRACE(Kernel, "Timer %u fired", timer_handle); + +    timer->signaled = true; + +    // Resume all waiting threads +    for (Handle thread : timer->waiting_threads) +        ResumeThreadFromWait(thread); + +    timer->waiting_threads.clear(); + +    if (timer->reset_type == RESETTYPE_ONESHOT) +        timer->signaled = false; + +    if (timer->interval_delay != 0) { +        // Reschedule the timer with the interval delay +        u64 interval_microseconds = timer->interval_delay / 1000; +        CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,  +                TimerCallbackEventType, timer_handle); +    } +} + +ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { +    Timer* timer = Kernel::g_handle_table.Get<Timer>(handle); + +    if (timer == nullptr) +        return InvalidHandle(ErrorModule::Kernel); + +    timer->initial_delay = initial; +    timer->interval_delay = interval; + +    u64 initial_microseconds = initial / 1000; +    CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), TimerCallbackEventType, handle); +    return RESULT_SUCCESS; +} + +ResultCode CancelTimer(Handle handle) { +    Timer* timer = Kernel::g_handle_table.Get<Timer>(handle); + +    if (timer == nullptr) +        return InvalidHandle(ErrorModule::Kernel); + +    CoreTiming::UnscheduleEvent(TimerCallbackEventType, handle); +    return RESULT_SUCCESS; +} + +void TimersInit() { +    TimerCallbackEventType = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); +} + +void TimersShutdown() { +} + +} // namespace diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h new file mode 100644 index 000000000..f8aa66b60 --- /dev/null +++ b/src/core/hle/kernel/timer.h @@ -0,0 +1,47 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" +#include "core/hle/svc.h" + +namespace Kernel { + +/** + * Cancels a timer + * @param handle Handle of the timer to cancel + */ +ResultCode CancelTimer(Handle handle); + +/** + * Starts a timer with the specified initial delay and interval + * @param handle Handle of the timer to start + * @param initial Delay until the timer is first fired + * @param interval Delay until the timer is fired after the first time + */ +ResultCode SetTimer(Handle handle, s64 initial, s64 interval); + +/** + * Clears a timer + * @param handle Handle of the timer to clear + */ +ResultCode ClearTimer(Handle handle); + +/** + * Creates a timer + * @param Handle to newly created Timer object + * @param reset_type ResetType describing how to create the timer + * @param name Optional name of timer + * @return ResultCode of the error + */ +ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name="Unknown"); + +/// Initializes the required variables for timers +void TimersInit(); +/// Tears down the timer variables +void TimersShutdown(); +} // namespace | 
