Created
November 23, 2019 14:08
-
-
Save lemon32767/f5a1f022717103be3203425bf1a670a7 to your computer and use it in GitHub Desktop.
thin wrapper around SDL_Thread's in zig
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//////////////////////////////////////////////////////////////////////////////////// | |
// | |
// 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