private static void init() { registerInit("LockOSThreadMain", () => { // init is guaranteed to run on the main thread. mainThread = C.pthread_self(); }); register("LockOSThreadMain", LockOSThreadMain); registerInit("LockOSThreadAlt", () => { // Lock the OS thread now so main runs on the main thread. runtime.LockOSThread(); }); register("LockOSThreadAlt", LockOSThreadAlt); }
public static void LockOSThreadAlt() { // This is running locked to the main OS thread. C.pthread_t subThread = default; var ready = make_channel <bool>(1L); C.threadExited = 0L; go_(() => () => { // This goroutine must be running on a new thread. runtime.LockOSThread(); subThread = C.pthread_self(); // Register a pthread destructor so we can tell this // thread has exited. ref C.pthread_key_t key = ref heap(out ptr <C.pthread_key_t> _addr_key); C.pthread_key_create(_addr_key, new ptr <ptr <array <byte> > >(@unsafe.Pointer(C.setExited))); C.pthread_setspecific(key, @unsafe.Pointer(@new <int>())); ready.Send(true); // Exit with the thread locked. } ());
public static void LockOSThreadMain() { // This requires GOMAXPROCS=1 from the beginning to reliably // start a goroutine on the main thread. if (runtime.GOMAXPROCS(-1L) != 1L) { println("requires GOMAXPROCS=1"); os.Exit(1L); } var ready = make_channel <bool>(1L); go_(() => () => { // Because GOMAXPROCS=1, this *should* be on the main // thread. Stay there. runtime.LockOSThread(); var self = C.pthread_self(); if (C.pthread_equal(mainThread, self) == 0L) { println("failed to start goroutine on main thread"); os.Exit(1L); } // Exit with the thread locked, which should exit the // main thread. ready.Send(true); } ()); ready.Receive(); time.Sleep(1L * time.Millisecond); // Check that this goroutine is still running on a different // thread. self = C.pthread_self(); if (C.pthread_equal(mainThread, self) != 0L) { println("goroutine migrated to locked thread"); os.Exit(1L); } println("OK"); }