Skip to content

Instantly share code, notes, and snippets.

@lemon32767
Created November 23, 2019 14:08
Show Gist options
  • Save lemon32767/f5a1f022717103be3203425bf1a670a7 to your computer and use it in GitHub Desktop.
Save lemon32767/f5a1f022717103be3203425bf1a670a7 to your computer and use it in GitHub Desktop.
thin wrapper around SDL_Thread's in zig
////////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2019 lemon sherbet
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software
// for any purpose, including commercial applications, and to alter it
// and redistribute it freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you
// must not claim that you wrote the original software. If you
// use this software in a product, an acknowledgment in the
// product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and
// must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////////////////////////////
const std = @import("std");
const c = @cImport({
@cInclude("SDL2/SDL.h");
});
//create an sdl thread:
// func must be a function taking
// one pointer parameter
// and returning void or a value as big as a c_int (could be an i32, for example)
// name is a c string that serves as an identifier for the sdl thread, optional
// data is the data passed to the function as its first parameter, must match the type
pub fn create(comptime func: var, name: [*c]const u8, data: var) !Thread(@typeInfo(@typeOf(func)).Fn.return_type.?) {
if (@typeInfo(@typeOf(func)).Fn.args[0].arg_type.? != @typeOf(data)) {
@compileError("type mismatch between function argument and data");
}
comptime const returnType = @typeInfo(@typeOf(func)).Fn.return_type.?;
if (returnType != void and @sizeOf(returnType) != @sizeOf(c_int)) {
@compileError("thread function return type must be exactly as wide as c_int");
}
if (@typeInfo(@typeOf(func)).Fn.args.len != 1) {
@compileError("thread function must take exactly one argument");
}
comptime const dataType = @typeOf(data);
comptime const c_fn = struct {
pub extern fn _(cdata: ?*c_void) c_int { //c callback wrapper
var userdata = @intToPtr(dataType, @ptrToInt(cdata)); //hackish
var ret = func(userdata);
return if (returnType == void) 0 else @bitCast(c_int, ret); //hackish
}
}._;
var handle = c.SDL_CreateThread(c_fn, name, @ptrCast(?*c_void, data)); //hackish
if (handle != null) {
return Thread(returnType) {
.handle = handle,
.detached = false,
.waited = false,
};
}
return error.SdlCreateThread;
}
//wrapper over SDL_Thread, with some safety checks and agnostic return type
fn Thread(comptime returnType: type) type {
return struct {
handle: ?*c.SDL_Thread,
detached: bool, //whether SDL_DetachThread has been called
waited: bool, //whether SDL_WaitThread has been called
//wait for thread to finish and get its return value
pub fn wait(self: *@This()) returnType {
std.debug.assert(!self.detached); //can't wait for detached thread
std.debug.assert(!self.waited); //can't wait for thread twice
var ret: c_int = undefined;
c.SDL_WaitThread(self.handle, &ret);
self.waited = true;
if (returnType != void) return @bitCast(returnType, ret);
}
pub fn detach(self: *@This()) void {
std.debug.assert(!self.waited); //can't detach waited for thread
std.debug.assert(!self.detached); //can't detach thread twice
c.SDL_DetachThread(self.handle);
self.detached = true;
}
pub fn getId(self: @This()) c.SDL_threadID {
return c.SDL_GetThreadID(self.handle);
}
pub fn getName(self: @This()) [*c]const u8 {
return c.SDL_GetThreadName(self.handle);
}
};
}
//get id of caller thread
pub fn getSelfId() c.SDL_threadID {
return c.SDL_GetThreadID(null);
}
//////////////////////
fn test_fac(n: *f32) f32 {
if (n.* <= 1) return 1;
var n2: f32 = n.* - 1;
return n.* * test_fac(&n2);
}
fn test_findprimes(max: *u32) void {
var n: u32 = 0;
var count: u32 = 0;
const isprime = struct {fn _(k: u32) bool {
var i: u32 = 2;
while (i < k/2) : (i += 1) {
if (k % i == 0) return false;
}
return true;
}}._;
while (n < max.*) : (n += 1) {
if (isprime(n)) count += 1;
}
std.debug.warn("thread {x}: {} primes\n", getSelfId(), count);
}
// zig test -L/usr/lib -lSDL2 -lc -I /usr/include sdlthread.zig
test "sdl thread" {
_ = c.SDL_Init(0);
defer c.SDL_Quit();
var thrd1 = try create(test_findprimes, c"prime finder", &@as(u32, 3000));
thrd1.detach();
var thrd2 = try create(test_fac, null, &@as(f32, 30));
std.debug.warn("\n");
std.debug.warn("fac(30) = {}\n", thrd2.wait());
c.SDL_Delay(150);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment