https://github.com/halide/Halide
Raw File
Tip revision: b4569042d1bd442b9dcf6817725297f427b9c20b authored by Steven Johnson on 25 June 2019, 22:05:55 UTC
forward-declare halide_buffer_t_accessor
Tip revision: b456904
windows_threads.cpp
#include "HalideRuntime.h"
#include "runtime_internal.h"

// TODO: consider getting rid of this
#define MAX_THREADS 256

extern "C" {

#ifdef BITS_64
#define WIN32API
#else
#define WIN32API __stdcall
#endif

// These sizes are large enough for 32-bit and 64-bit
typedef uint64_t ConditionVariable;
typedef void * Thread;
typedef struct {
    uint64_t buf[5];
} CriticalSection;

extern WIN32API Thread CreateThread(void *, size_t, void *(*fn)(void *), void *, int32_t, int32_t *);
extern WIN32API void InitializeConditionVariable(ConditionVariable *);
extern WIN32API void WakeConditionVariable(ConditionVariable *);
extern WIN32API void SleepConditionVariableCS(ConditionVariable *, CriticalSection *, int);
extern WIN32API void InitializeCriticalSection(CriticalSection *);
extern WIN32API void DeleteCriticalSection(CriticalSection *);
extern WIN32API void EnterCriticalSection(CriticalSection *);
extern WIN32API void LeaveCriticalSection(CriticalSection *);
extern WIN32API int32_t WaitForSingleObject(Thread, int32_t timeout);

} // extern "C"

namespace Halide { namespace Runtime { namespace Internal {

struct spawned_thread {
    void(*f)(void *);
    void *closure;
    Thread handle;
};
WEAK void *spawn_thread_helper(void *arg) {
    spawned_thread *t = (spawned_thread *)arg;
    t->f(t->closure);
    return NULL;
}

}}} // namespace Halide::Runtime::Internal

extern "C" {

WEAK int halide_host_cpu_count() {
    // Apparently a standard windows environment variable
    char *num_cores = getenv("NUMBER_OF_PROCESSORS");
    if (num_cores) {
        return atoi(num_cores);
    } else {
        return 8;
    }
}

WEAK halide_thread *halide_spawn_thread(void(*f)(void *), void *closure) {
    spawned_thread *t = (spawned_thread *)malloc(sizeof(spawned_thread));
    t->f = f;
    t->closure = closure;
    t->handle = CreateThread(NULL, 0, spawn_thread_helper, t, 0, NULL);
    return (halide_thread *)t;
}

WEAK void halide_join_thread(halide_thread *thread_arg) {
    spawned_thread *thread = (spawned_thread *)thread_arg;
    WaitForSingleObject(thread->handle, -1);
    free(thread);
}

} // extern "C"

namespace Halide { namespace Runtime { namespace Internal {

namespace Synchronization {

struct thread_parker {
    CriticalSection critical_section;
    ConditionVariable condvar;
    bool should_park;

#if __cplusplus >= 201103L
    thread_parker(const thread_parker &) = delete;
#endif

    __attribute__((always_inline)) thread_parker() : should_park(false) {
        InitializeCriticalSection(&critical_section);
        InitializeConditionVariable(&condvar);
        should_park = false;
    }

    __attribute__((always_inline)) ~thread_parker() {
        // Windows ConditionVariable objects do not need to be deleted. There is no API to do so.
        DeleteCriticalSection(&critical_section);
    }

    __attribute__((always_inline)) void prepare_park() {
        should_park = true;
    }

    __attribute__((always_inline)) void park() {
        EnterCriticalSection(&critical_section);
        while (should_park) {
            SleepConditionVariableCS(&condvar, &critical_section, -1);
        }
        LeaveCriticalSection(&critical_section);
    }

    __attribute__((always_inline)) void unpark_start() {
        EnterCriticalSection(&critical_section);
    }

    __attribute__((always_inline)) void unpark() {
        should_park = false;
        WakeConditionVariable(&condvar);
    }

    __attribute__((always_inline)) void unpark_finish() {
        LeaveCriticalSection(&critical_section);
    }
};

}}}} // namespace Halide::Runtime::Internal::Synchronization

#include "synchronization_common.h"

#include "thread_pool_common.h"

back to top