Python: Add runner, thread interfaces

This commit is contained in:
Vicki Pfau 2017-06-22 22:07:08 -07:00
parent e1325b0373
commit dce49ea990
4 changed files with 109 additions and 0 deletions

View File

@ -1,5 +1,6 @@
#define COMMON_H
#define PNG_H
#define OPAQUE_THREADING
#define _SYS_TIME_H
#define _SYS_TIME_H_
#define _TIME_H
@ -30,6 +31,7 @@ void free(void*);
#include <mgba/core/core.h>
#include <mgba/core/mem-search.h>
#include <mgba/core/tile-cache.h>
#include <mgba/core/thread.h>
#include <mgba/core/version.h>
#define PYEXPORT extern "Python+C"

View File

@ -18,10 +18,12 @@ cppflags.extend(["-I" + incdir, "-I" + srcdir, "-I" + bindir])
ffi.set_source("mgba._pylib", """
#include "flags.h"
#define OPAQUE_THREADING
#include <mgba-util/common.h>
#include <mgba/core/core.h>
#include <mgba/core/log.h>
#include <mgba/core/mem-search.h>
#include <mgba/core/thread.h>
#include <mgba/core/tile-cache.h>
#include <mgba/core/version.h>
#include <mgba/internal/arm/arm.h>

View File

@ -38,10 +38,18 @@ def needsReset(f):
return f(self, *args, **kwargs)
return wrapper
def protected(f):
def wrapper(self, *args, **kwargs):
if self._protected:
raise RuntimeError("Core is protected")
return f(self, *args, **kwargs)
return wrapper
class Core(object):
def __init__(self, native):
self._core = native
self._wasReset = False
self._protected = False
@cached_property
def tiles(self):
@ -51,6 +59,7 @@ class Core(object):
def _init(cls, native):
core = ffi.gc(native, native.deinit)
success = bool(core.init(core))
lib.mCoreInitConfig(core, ffi.NULL)
if not success:
raise RuntimeError("Failed to initialize core")
if hasattr(cls, 'PLATFORM_GBA') and core.platform(core) == cls.PLATFORM_GBA:
@ -62,6 +71,7 @@ class Core(object):
def _deinit(self):
self._core.deinit(self._core)
@protected
def loadFile(self, path):
return bool(lib.mCoreLoadFile(self._core, path.encode('UTF-8')))
@ -77,6 +87,7 @@ class Core(object):
def loadTemporarySave(self, vf):
return bool(self._core.loadTemporarySave(self._core, vf.handle))
@protected
def loadPatch(self, vf):
return bool(self._core.loadPatch(self._core, vf.handle))
@ -98,19 +109,23 @@ class Core(object):
def setVideoBuffer(self, image):
self._core.setVideoBuffer(self._core, image.buffer, image.stride)
@protected
def reset(self):
self._core.reset(self._core)
self._wasReset = True
@needsReset
@protected
def runFrame(self):
self._core.runFrame(self._core)
@needsReset
@protected
def runLoop(self):
self._core.runLoop(self._core)
@needsReset
@protected
def step(self):
self._core.step(self._core)
@ -152,6 +167,38 @@ class Core(object):
self._core.getGameCode(self._core, code)
return ffi.string(code, 12).decode("ascii")
class ICoreOwner(object):
def claim(self):
raise NotImplementedError
def release(self):
raise NotImplementedError
def __enter__(self):
self.core = self.claim()
self.core._protected = True
return self.core
def __exit__(self, type, value, traceback):
self.core._protected = False
self.release()
class IRunner(object):
def pause(self):
raise NotImplementedError
def unpause(self):
raise NotImplementedError
def useCore(self):
raise NotImplementedError
def isRunning(self):
raise NotImplementedError
def isPaused(self):
raise NotImplementedError
if hasattr(lib, 'PLATFORM_GBA'):
from .gba import GBA
Core.PLATFORM_GBA = lib.PLATFORM_GBA

View File

@ -0,0 +1,58 @@
# Copyright (c) 2013-2017 Jeffrey Pfau
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib
from .core import IRunner, ICoreOwner, Core
class ThreadCoreOwner(ICoreOwner):
def __init__(self, thread):
self.thread = thread
def claim(self):
if not self.thread.isRunning():
raise ValueError
lib.mCoreThreadInterrupt(self.thread._native)
return self.thread._core
def release(self):
lib.mCoreThreadContinue(self.thread._native)
class Thread(IRunner):
def __init__(self, native=None):
if native:
self._native = native
self._core = Core(native.core)
self._core._wasReset = lib.mCoreThreadHasStarted(self._native)
else:
self._native = ffi.new("struct mCoreThread*")
def start(self, core):
if lib.mCoreThreadHasStarted(self._native):
raise ValueError
self._core = core
self._native.core = core._core
lib.mCoreThreadStart(self._native)
self._core._wasReset = lib.mCoreThreadHasStarted(self._native)
def end(self):
if not lib.mCoreThreadHasStarted(self._native):
raise ValueError
lib.mCoreThreadEnd(self._native)
lib.mCoreThreadJoin(self._native)
def pause(self):
lib.mCoreThreadPause(self._native)
def unpause(self):
lib.mCoreThreadUnpause(self._native)
def isRunning(self):
return bool(lib.mCoreThreadIsActive(self._native))
def isPaused(self):
return bool(lib.mCoreThreadIsPaused(self._native))
def useCore(self):
return ThreadCoreOwner(self)