...

Text file src/runtime/cgo/gcc_darwin_arm.c

     1	// Copyright 2014 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	#include <limits.h>
     6	#include <pthread.h>
     7	#include <signal.h>
     8	#include <string.h> /* for strerror */
     9	#include <sys/param.h>
    10	#include <unistd.h>
    11	
    12	#include <CoreFoundation/CFBundle.h>
    13	#include <CoreFoundation/CFString.h>
    14	
    15	#include "libcgo.h"
    16	#include "libcgo_unix.h"
    17	
    18	#define magic (0xe696c4f4U)
    19	
    20	// inittls allocates a thread-local storage slot for g.
    21	//
    22	// It finds the first available slot using pthread_key_create and uses
    23	// it as the offset value for runtime.tlsg.
    24	static void
    25	inittls(void **tlsg, void **tlsbase)
    26	{
    27		pthread_key_t k;
    28		int i, err;
    29	
    30		err = pthread_key_create(&k, nil);
    31		if(err != 0) {
    32			fprintf(stderr, "runtime/cgo: pthread_key_create failed: %d\n", err);
    33			abort();
    34		}
    35		//fprintf(stderr, "runtime/cgo: k = %d, tlsbase = %p\n", (int)k, tlsbase); // debug
    36		pthread_setspecific(k, (void*)magic);
    37		// The first key should be at 258.
    38		for (i=0; i<PTHREAD_KEYS_MAX; i++) {
    39			if (*(tlsbase+i) == (void*)magic) {
    40				*tlsg = (void*)(i*sizeof(void *));
    41				pthread_setspecific(k, 0);
    42				return;
    43			}
    44		}
    45		fprintf(stderr, "runtime/cgo: could not find pthread key.\n");
    46		abort();
    47	}
    48	
    49	static void *threadentry(void*);
    50	static void (*setg_gcc)(void*);
    51	
    52	void
    53	_cgo_sys_thread_start(ThreadStart *ts)
    54	{
    55		pthread_attr_t attr;
    56		sigset_t ign, oset;
    57		pthread_t p;
    58		size_t size;
    59		int err;
    60	
    61		sigfillset(&ign);
    62		pthread_sigmask(SIG_SETMASK, &ign, &oset);
    63	
    64		pthread_attr_init(&attr);
    65		size = 0;
    66		pthread_attr_getstacksize(&attr, &size);
    67		// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
    68		ts->g->stackhi = size;
    69		err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
    70	
    71		pthread_sigmask(SIG_SETMASK, &oset, nil);
    72	
    73		if (err != 0) {
    74			fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
    75			abort();
    76		}
    77	}
    78	
    79	extern void crosscall_arm1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
    80	static void*
    81	threadentry(void *v)
    82	{
    83		ThreadStart ts;
    84	
    85		ts = *(ThreadStart*)v;
    86		free(v);
    87	
    88		darwin_arm_init_thread_exception_port();
    89	
    90		crosscall_arm1(ts.fn, setg_gcc, (void*)ts.g);
    91		return nil;
    92	}
    93	
    94	// init_working_dir sets the current working directory to the app root.
    95	// By default darwin/arm processes start in "/".
    96	static void
    97	init_working_dir()
    98	{
    99		CFBundleRef bundle = CFBundleGetMainBundle();
   100		if (bundle == NULL) {
   101			fprintf(stderr, "runtime/cgo: no main bundle\n");
   102			return;
   103		}
   104		CFURLRef url_ref = CFBundleCopyResourceURL(bundle, CFSTR("Info"), CFSTR("plist"), NULL);
   105		if (url_ref == NULL) {
   106			// No Info.plist found. It can happen on Corellium virtual devices.
   107			return;
   108		}
   109		CFStringRef url_str_ref = CFURLGetString(url_ref);
   110		char buf[MAXPATHLEN];
   111		Boolean res = CFStringGetCString(url_str_ref, buf, sizeof(buf), kCFStringEncodingUTF8);
   112		CFRelease(url_ref);
   113		if (!res) {
   114			fprintf(stderr, "runtime/cgo: cannot get URL string\n");
   115			return;
   116		}
   117	
   118		// url is of the form "file:///path/to/Info.plist".
   119		// strip it down to the working directory "/path/to".
   120		int url_len = strlen(buf);
   121		if (url_len < sizeof("file://")+sizeof("/Info.plist")) {
   122			fprintf(stderr, "runtime/cgo: bad URL: %s\n", buf);
   123			return;
   124		}
   125		buf[url_len-sizeof("/Info.plist")+1] = 0;
   126		char *dir = &buf[0] + sizeof("file://")-1;
   127	
   128		if (chdir(dir) != 0) {
   129			fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", dir);
   130		}
   131	
   132		// The test harness in go_darwin_arm_exec passes the relative working directory
   133		// in the GoExecWrapperWorkingDirectory property of the app bundle.
   134		CFStringRef wd_ref = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("GoExecWrapperWorkingDirectory"));
   135		if (wd_ref != NULL) {
   136			if (!CFStringGetCString(wd_ref, buf, sizeof(buf), kCFStringEncodingUTF8)) {
   137				fprintf(stderr, "runtime/cgo: cannot get GoExecWrapperWorkingDirectory string\n");
   138				return;
   139			}
   140			if (chdir(buf) != 0) {
   141				fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", buf);
   142			}
   143		}
   144	}
   145	
   146	void
   147	x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
   148	{
   149		pthread_attr_t attr;
   150		size_t size;
   151	
   152		setg_gcc = setg;
   153		pthread_attr_init(&attr);
   154		pthread_attr_getstacksize(&attr, &size);
   155		g->stacklo = (uintptr)&attr - size + 4096;
   156		pthread_attr_destroy(&attr);
   157	
   158		// yes, tlsbase from mrc might not be correctly aligned.
   159		inittls(tlsg, (void**)((uintptr)tlsbase & ~3));
   160	
   161		darwin_arm_init_mach_exception_handler();
   162		darwin_arm_init_thread_exception_port();
   163		init_working_dir();
   164	}

View as plain text