Skip to content

Commit

Permalink
Add workaround for cross-compiler without std::mutex.
Browse files Browse the repository at this point in the history
Refs ticket:4496.
  • Loading branch information
Cyp committed Sep 5, 2016
1 parent 5b9e3b4 commit a789487
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 15 deletions.
85 changes: 85 additions & 0 deletions lib/framework/wzapp.h
Expand Up @@ -76,4 +76,89 @@ WZ_DECL_NONNULL(1) void wzSemaphoreDestroy(WZ_SEMAPHORE *semaphore);
WZ_DECL_NONNULL(1) void wzSemaphoreWait(WZ_SEMAPHORE *semaphore);
WZ_DECL_NONNULL(1) void wzSemaphorePost(WZ_SEMAPHORE *semaphore);

#if !defined(WZ_CC_MINGW)

#include <mutex>
#include <future>

namespace wz
{
using mutex = std::mutex;
template <typename R>
using future = std::future<R>;
template <typename RA>
using packaged_task = std::packaged_task<RA>;
}

#else // Workaround for cross-compiler without std::mutex.

#include <memory>

namespace wz
{
class mutex
{
public:
mutex() : handle(wzMutexCreate()) {}
~mutex() { wzMutexDestroy(handle); }

mutex(mutex const &) = delete;
mutex &operator =(mutex const &) = delete;

void lock() { wzMutexLock(handle); }
//bool try_lock();
void unlock() { wzMutexUnlock(handle); }

private:
WZ_MUTEX *handle;
};

template <typename R>
class future
{
public:
future() = default;
future(future &&other) : internal(std::move(other.internal)) {}
future(future const &) = delete;
future &operator =(future &&other) = default;
future &operator =(future const &) = delete;
//std::shared_future<T> share();
R get() { auto &data = *internal; wzSemaphoreWait(data.sem); return std::move(data.ret); }
//valid(), wait*();

struct Internal // Should really be a promise.
{
Internal() : sem(wzSemaphoreCreate(0)) {}
~Internal() { wzSemaphoreDestroy(sem); }
R ret;
WZ_SEMAPHORE *sem;
};

std::shared_ptr<Internal> internal;
};

template <typename RA>
class packaged_task;

template <typename R, typename... A>
class packaged_task<R (A...)>
{
public:
packaged_task() = default;
template <typename F>
explicit packaged_task(F &&f) { function = std::move(f); internal = std::make_shared<typename future<R>::Internal>(); }
packaged_task(packaged_task &&) = default;
packaged_task(packaged_task const &) = delete;

future<R> get_future() { future<R> future; future.internal = internal; return std::move(future); }
void operator ()(A... args) { auto &data = *internal; data.ret = function(std::forward<A>(args)...); wzSemaphorePost(data.sem); }

private:
std::function<R (A...)> function;
std::shared_ptr<typename future<R>::Internal> internal;
};
}

#endif

#endif
20 changes: 5 additions & 15 deletions src/fpath.cpp
Expand Up @@ -64,9 +64,9 @@ struct PATHRESULT
static WZ_THREAD *fpathThread = NULL;
static WZ_MUTEX *fpathMutex = NULL;
static WZ_SEMAPHORE *fpathSemaphore = NULL;
using packagedPathJob = std::packaged_task<PATHRESULT()>;
using packagedPathJob = wz::packaged_task<PATHRESULT()>;
static std::list<packagedPathJob> pathJobs;
static std::unordered_map<uint32_t, std::future<PATHRESULT>> pathResults;
static std::unordered_map<uint32_t, wz::future<PATHRESULT>> pathResults;

static bool waitingForResult = false;
static uint32_t waitingForResultId;
Expand Down Expand Up @@ -94,9 +94,8 @@ static int fpathThreadFunc(void *)
// Copy the first job from the queue.
packagedPathJob job = std::move(pathJobs.front());
pathJobs.pop_front();
wzMutexUnlock(fpathMutex);

// we need to lock BEFORE we fiddle with the data, or we get ugly data race conditions.
wzMutexUnlock(fpathMutex);
job();
wzMutexLock(fpathMutex);

Expand Down Expand Up @@ -318,7 +317,7 @@ void fpathRemoveDroidData(int id)
pathResults.erase(id);
}

static FPATH_RETVAL fpathRoute(MOVE_CONTROL *psMove, int id, int startX, int startY, int tX, int tY, PROPULSION_TYPE propulsionType,
static FPATH_RETVAL fpathRoute(MOVE_CONTROL *psMove, unsigned id, int startX, int startY, int tX, int tY, PROPULSION_TYPE propulsionType,
DROID_TYPE droidType, FPATH_MOVETYPE moveType, int owner, bool acceptNearest, StructureBounds const &dstStructure)
{
objTrace(id, "called(*,id=%d,sx=%d,sy=%d,ex=%d,ey=%d,prop=%d,type=%d,move=%d,owner=%d)", id, startX, startY, tX, tY, (int)propulsionType, (int)droidType, (int)moveType, owner);
Expand Down Expand Up @@ -346,16 +345,7 @@ static FPATH_RETVAL fpathRoute(MOVE_CONTROL *psMove, int id, int startX, int sta
objTrace(id, "Checking if we have a path yet");

auto const &I = pathResults.find(id);
assert(I != pathResults.end());
bool isReady = I->second.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
if (!isReady)
{
objTrace(id, "No path yet. Waiting.");
waitingForResult = true;
waitingForResultId = id;
wzSemaphoreWait(waitingForResultSemaphore); // keep waiting
continue;
}
ASSERT(I != pathResults.end(), "Missing path result promise");
PATHRESULT result = I->second.get();
ASSERT(result.retval != FPR_OK || result.sMove.asPath, "Ok result but no path in list");

Expand Down

0 comments on commit a789487

Please sign in to comment.