github.com/hongwozai/go-src-1.4.3@v0.0.0-20191127132709-dc3fce3dbccb/src/cmd/dist/unix.c (about)

     1  // Copyright 2012 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  // These #ifdefs are being used as a substitute for
     6  // build configuration, so that on any system, this
     7  // tool can be built with the local equivalent of
     8  //	cc *.c
     9  //
    10  #ifndef WIN32
    11  #ifndef PLAN9
    12  
    13  #include "a.h"
    14  #include <unistd.h>
    15  #include <dirent.h>
    16  #include <sys/stat.h>
    17  #include <sys/wait.h>
    18  #include <sys/param.h>
    19  #include <sys/utsname.h>
    20  #include <fcntl.h>
    21  #include <string.h>
    22  #include <stdio.h>
    23  #include <stdlib.h>
    24  #include <errno.h>
    25  #include <stdarg.h>
    26  #include <setjmp.h>
    27  #include <signal.h>
    28  
    29  // bprintf replaces the buffer with the result of the printf formatting
    30  // and returns a pointer to the NUL-terminated buffer contents.
    31  char*
    32  bprintf(Buf *b, char *fmt, ...)
    33  {
    34  	va_list arg;
    35  	char buf[4096];
    36  	
    37  	breset(b);
    38  	va_start(arg, fmt);
    39  	vsnprintf(buf, sizeof buf, fmt, arg);
    40  	va_end(arg);
    41  	bwritestr(b, buf);
    42  	return bstr(b);
    43  }
    44  
    45  // bpathf is the same as bprintf (on windows it turns / into \ after the printf).
    46  // It returns a pointer to the NUL-terminated buffer contents.
    47  char*
    48  bpathf(Buf *b, char *fmt, ...)
    49  {
    50  	va_list arg;
    51  	char buf[4096];
    52  	
    53  	breset(b);
    54  	va_start(arg, fmt);
    55  	vsnprintf(buf, sizeof buf, fmt, arg);
    56  	va_end(arg);
    57  	bwritestr(b, buf);
    58  	return bstr(b);
    59  }
    60  
    61  // bwritef is like bprintf but does not reset the buffer
    62  // and does not return the NUL-terminated string.
    63  void
    64  bwritef(Buf *b, char *fmt, ...)
    65  {
    66  	va_list arg;
    67  	char buf[4096];
    68  	
    69  	va_start(arg, fmt);
    70  	vsnprintf(buf, sizeof buf, fmt, arg);
    71  	va_end(arg);
    72  	bwritestr(b, buf);
    73  }
    74  
    75  // breadfrom appends to b all the data that can be read from fd.
    76  static void
    77  breadfrom(Buf *b, int fd)
    78  {
    79  	int n;
    80  
    81  	for(;;) {
    82  		bgrow(b, 4096);
    83  		n = read(fd, b->p+b->len, 4096);
    84  		if(n < 0)
    85  			fatal("read: %s", strerror(errno));
    86  		if(n == 0)
    87  			break;
    88  		b->len += n;
    89  	}
    90  }
    91  
    92  // xgetenv replaces b with the value of the named environment variable.
    93  void
    94  xgetenv(Buf *b, char *name)
    95  {
    96  	char *p;
    97  	
    98  	breset(b);
    99  	p = getenv(name);
   100  	if(p != NULL)
   101  		bwritestr(b, p);
   102  }
   103  
   104  static void genrun(Buf *b, char *dir, int mode, Vec *argv, int bg);
   105  
   106  // run runs the command named by cmd.
   107  // If b is not nil, run replaces b with the output of the command.
   108  // If dir is not nil, run runs the command in that directory.
   109  // If mode is CheckExit, run calls fatal if the command is not successful.
   110  void
   111  run(Buf *b, char *dir, int mode, char *cmd, ...)
   112  {
   113  	va_list arg;
   114  	Vec argv;
   115  	char *p;
   116  	
   117  	vinit(&argv);
   118  	vadd(&argv, cmd);
   119  	va_start(arg, cmd);
   120  	while((p = va_arg(arg, char*)) != nil)
   121  		vadd(&argv, p);
   122  	va_end(arg);
   123  	
   124  	runv(b, dir, mode, &argv);
   125  	
   126  	vfree(&argv);
   127  }
   128  
   129  // runv is like run but takes a vector.
   130  void
   131  runv(Buf *b, char *dir, int mode, Vec *argv)
   132  {
   133  	genrun(b, dir, mode, argv, 1);
   134  }
   135  
   136  // bgrunv is like run but runs the command in the background.
   137  // bgwait waits for pending bgrunv to finish.
   138  void
   139  bgrunv(char *dir, int mode, Vec *argv)
   140  {
   141  	genrun(nil, dir, mode, argv, 0);
   142  }
   143  
   144  #define MAXBG 4 /* maximum number of jobs to run at once */
   145  
   146  static struct {
   147  	int pid;
   148  	int mode;
   149  	char *cmd;
   150  	Buf *b;
   151  } bg[MAXBG];
   152  static int nbg;
   153  static int maxnbg = nelem(bg);
   154  
   155  static void bgwait1(void);
   156  
   157  // genrun is the generic run implementation.
   158  static void
   159  genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
   160  {
   161  	int i, p[2], pid;
   162  	Buf cmd;
   163  	char *q;
   164  
   165  	while(nbg >= maxnbg)
   166  		bgwait1();
   167  
   168  	// Generate a copy of the command to show in a log.
   169  	// Substitute $WORK for the work directory.
   170  	binit(&cmd);
   171  	for(i=0; i<argv->len; i++) {
   172  		if(i > 0)
   173  			bwritestr(&cmd, " ");
   174  		q = argv->p[i];
   175  		if(workdir != nil && hasprefix(q, workdir)) {
   176  			bwritestr(&cmd, "$WORK");
   177  			q += strlen(workdir);
   178  		}
   179  		bwritestr(&cmd, q);
   180  	}
   181  	if(vflag > 1)
   182  		errprintf("%s\n", bstr(&cmd));
   183  
   184  	if(b != nil) {
   185  		breset(b);
   186  		if(pipe(p) < 0)
   187  			fatal("pipe: %s", strerror(errno));
   188  	}
   189  
   190  	switch(pid = fork()) {
   191  	case -1:
   192  		fatal("fork: %s", strerror(errno));
   193  	case 0:
   194  		if(b != nil) {
   195  			close(0);
   196  			close(p[0]);
   197  			dup2(p[1], 1);
   198  			dup2(p[1], 2);
   199  			if(p[1] > 2)
   200  				close(p[1]);
   201  		}
   202  		if(dir != nil) {
   203  			if(chdir(dir) < 0) {
   204  				fprintf(stderr, "chdir %s: %s\n", dir, strerror(errno));
   205  				_exit(1);
   206  			}
   207  		}
   208  		vadd(argv, nil);
   209          char buf[4096];
   210          int size = sprintf(buf, "exec ");
   211          for (i = 0; i < argv->len; i++) {
   212              int temp = sprintf(buf + size, " %s", argv->p[i]);
   213              size += temp;
   214          }
   215          printf("pid: %d, %.*s\n", getpid(), size, buf);
   216  		execvp(argv->p[0], argv->p);
   217  		fprintf(stderr, "%s\n", bstr(&cmd));
   218  		fprintf(stderr, "exec %s: %s\n", argv->p[0], strerror(errno));
   219  		_exit(1);
   220  	}
   221  	if(b != nil) {
   222  		close(p[1]);
   223  		breadfrom(b, p[0]);
   224  		close(p[0]);
   225  	}
   226  
   227  	if(nbg < 0)
   228  		fatal("bad bookkeeping");
   229  	bg[nbg].pid = pid;
   230  	bg[nbg].mode = mode;
   231  	bg[nbg].cmd = btake(&cmd);
   232  	bg[nbg].b = b;
   233  	nbg++;
   234  	
   235  	if(wait)
   236  		bgwait();
   237  
   238  	bfree(&cmd);
   239  }
   240  
   241  // bgwait1 waits for a single background job.
   242  static void
   243  bgwait1(void)
   244  {
   245  	int i, pid, status, mode;
   246  	char *cmd;
   247  	Buf *b;
   248  
   249  	errno = 0;
   250  	while((pid = wait(&status)) < 0) {
   251  		if(errno != EINTR)
   252  			fatal("waitpid: %s", strerror(errno));
   253  	}
   254  	for(i=0; i<nbg; i++)
   255  		if(bg[i].pid == pid)
   256  			goto ok;
   257  	fatal("waitpid: unexpected pid");
   258  
   259  ok:
   260  	cmd = bg[i].cmd;
   261  	mode = bg[i].mode;
   262  	bg[i].pid = 0;
   263  	b = bg[i].b;
   264  	bg[i].b = nil;
   265  	bg[i] = bg[--nbg];
   266  	
   267  	if(mode == CheckExit && (!WIFEXITED(status) || WEXITSTATUS(status) != 0)) {
   268  		if(b != nil)
   269  			xprintf("%s\n", bstr(b));
   270  		fatal("FAILED: %s", cmd);
   271  	}
   272  	xfree(cmd);
   273  }
   274  
   275  // bgwait waits for all the background jobs.
   276  void
   277  bgwait(void)
   278  {
   279  	while(nbg > 0)
   280  		bgwait1();
   281  }
   282  
   283  // xgetwd replaces b with the current directory.
   284  void
   285  xgetwd(Buf *b)
   286  {
   287  	char buf[MAXPATHLEN];
   288  	
   289  	breset(b);
   290  	if(getcwd(buf, MAXPATHLEN) == nil)
   291  		fatal("getcwd: %s", strerror(errno));
   292  	bwritestr(b, buf);	
   293  }
   294  
   295  // xrealwd replaces b with the 'real' name for the given path.
   296  // real is defined as what getcwd returns in that directory.
   297  void
   298  xrealwd(Buf *b, char *path)
   299  {
   300  	int fd;
   301  	
   302  	fd = open(".", 0);
   303  	if(fd < 0)
   304  		fatal("open .: %s", strerror(errno));
   305  	if(chdir(path) < 0)
   306  		fatal("chdir %s: %s", path, strerror(errno));
   307  	xgetwd(b);
   308  	if(fchdir(fd) < 0)
   309  		fatal("fchdir: %s", strerror(errno));
   310  	close(fd);
   311  }
   312  
   313  // isdir reports whether p names an existing directory.
   314  bool
   315  isdir(char *p)
   316  {
   317  	struct stat st;
   318  	
   319  	return stat(p, &st) >= 0 && S_ISDIR(st.st_mode);
   320  }
   321  
   322  // isfile reports whether p names an existing file.
   323  bool
   324  isfile(char *p)
   325  {
   326  	struct stat st;
   327  	
   328  	return stat(p, &st) >= 0 && S_ISREG(st.st_mode);
   329  }
   330  
   331  // mtime returns the modification time of the file p.
   332  Time
   333  mtime(char *p)
   334  {
   335  	struct stat st;
   336  	
   337  	if(stat(p, &st) < 0)
   338  		return 0;
   339  	return (Time)st.st_mtime*1000000000LL;
   340  }
   341  
   342  // isabs reports whether p is an absolute path.
   343  bool
   344  isabs(char *p)
   345  {
   346  	return hasprefix(p, "/");
   347  }
   348  
   349  // readfile replaces b with the content of the named file.
   350  void
   351  readfile(Buf *b, char *file)
   352  {
   353  	int fd;
   354  	
   355  	breset(b);
   356  	fd = open(file, 0);
   357  	if(fd < 0)
   358  		fatal("open %s: %s", file, strerror(errno));
   359  	breadfrom(b, fd);
   360  	close(fd);
   361  }
   362  
   363  // writefile writes b to the named file, creating it if needed.  if
   364  // exec is non-zero, marks the file as executable.
   365  void
   366  writefile(Buf *b, char *file, int exec)
   367  {
   368  	int fd;
   369  	
   370  	fd = creat(file, 0666);
   371  	if(fd < 0)
   372  		fatal("create %s: %s", file, strerror(errno));
   373  	if(write(fd, b->p, b->len) != b->len)
   374  		fatal("short write: %s", strerror(errno));
   375  	if(exec)
   376  		fchmod(fd, 0755);
   377  	close(fd);
   378  }
   379  
   380  // xmkdir creates the directory p.
   381  void
   382  xmkdir(char *p)
   383  {
   384  	if(mkdir(p, 0777) < 0)
   385  		fatal("mkdir %s: %s", p, strerror(errno));
   386  }
   387  
   388  // xmkdirall creates the directory p and its parents, as needed.
   389  void
   390  xmkdirall(char *p)
   391  {
   392  	char *q;
   393  
   394  	if(isdir(p))
   395  		return;
   396  	q = strrchr(p, '/');
   397  	if(q != nil) {
   398  		*q = '\0';
   399  		xmkdirall(p);
   400  		*q = '/';
   401  	}
   402  	xmkdir(p);
   403  }
   404  
   405  // xremove removes the file p.
   406  void
   407  xremove(char *p)
   408  {
   409  	if(vflag > 2)
   410  		errprintf("rm %s\n", p);
   411  	unlink(p);
   412  }
   413  
   414  // xremoveall removes the file or directory tree rooted at p.
   415  void
   416  xremoveall(char *p)
   417  {
   418  	int i;
   419  	Buf b;
   420  	Vec dir;
   421  
   422  	binit(&b);
   423  	vinit(&dir);
   424  
   425  	if(isdir(p)) {
   426  		xreaddir(&dir, p);
   427  		for(i=0; i<dir.len; i++) {
   428  			bprintf(&b, "%s/%s", p, dir.p[i]);
   429  			xremoveall(bstr(&b));
   430  		}
   431  		if(vflag > 2)
   432  			errprintf("rm %s\n", p);
   433  		rmdir(p);
   434  	} else {
   435  		if(vflag > 2)
   436  			errprintf("rm %s\n", p);
   437  		unlink(p);
   438  	}
   439  	
   440  	bfree(&b);
   441  	vfree(&dir);
   442  }
   443  
   444  // xreaddir replaces dst with a list of the names of the files in dir.
   445  // The names are relative to dir; they are not full paths.
   446  void
   447  xreaddir(Vec *dst, char *dir)
   448  {
   449  	DIR *d;
   450  	struct dirent *dp;
   451  
   452  	vreset(dst);
   453  	d = opendir(dir);
   454  	if(d == nil)
   455  		fatal("opendir %s: %s", dir, strerror(errno));
   456  	while((dp = readdir(d)) != nil) {
   457  		if(streq(dp->d_name, ".") || streq(dp->d_name, ".."))
   458  			continue;
   459  		vadd(dst, dp->d_name);
   460  	}
   461  	closedir(d);
   462  }
   463  
   464  // xworkdir creates a new temporary directory to hold object files
   465  // and returns the name of that directory.
   466  char*
   467  xworkdir(void)
   468  {
   469  	Buf b;
   470  	char *p;
   471  
   472  	binit(&b);
   473  
   474  	xgetenv(&b, "TMPDIR");
   475  	if(b.len == 0)
   476  		bwritestr(&b, "/var/tmp");
   477  	if(b.p[b.len-1] != '/')
   478  		bwrite(&b, "/", 1);
   479  	bwritestr(&b, "go-cbuild-XXXXXX");
   480  	p = bstr(&b);
   481  	if(mkdtemp(p) == nil)
   482  		fatal("mkdtemp(%s): %s", p, strerror(errno));
   483  	p = btake(&b);
   484  
   485  	bfree(&b);
   486  
   487  	return p;
   488  }
   489  
   490  // fatal prints an error message to standard error and exits.
   491  void
   492  fatal(char *msg, ...)
   493  {
   494  	va_list arg;
   495  	
   496  	fflush(stdout);
   497  	fprintf(stderr, "go tool dist: ");
   498  	va_start(arg, msg);
   499  	vfprintf(stderr, msg, arg);
   500  	va_end(arg);
   501  	fprintf(stderr, "\n");
   502  	
   503  	bgwait();
   504  	exit(1);
   505  }
   506  
   507  // xmalloc returns a newly allocated zeroed block of n bytes of memory.
   508  // It calls fatal if it runs out of memory.
   509  void*
   510  xmalloc(int n)
   511  {
   512  	void *p;
   513  	
   514  	p = malloc(n);
   515  	if(p == nil)
   516  		fatal("out of memory");
   517  	memset(p, 0, n);
   518  	return p;
   519  }
   520  
   521  // xstrdup returns a newly allocated copy of p.
   522  // It calls fatal if it runs out of memory.
   523  char*
   524  xstrdup(char *p)
   525  {
   526  	p = strdup(p);
   527  	if(p == nil)
   528  		fatal("out of memory");
   529  	return p;
   530  }
   531  
   532  // xrealloc grows the allocation p to n bytes and
   533  // returns the new (possibly moved) pointer.
   534  // It calls fatal if it runs out of memory.
   535  void*
   536  xrealloc(void *p, int n)
   537  {
   538  	p = realloc(p, n);
   539  	if(p == nil)
   540  		fatal("out of memory");
   541  	return p;
   542  }
   543  
   544  // xfree frees the result returned by xmalloc, xstrdup, or xrealloc.
   545  void
   546  xfree(void *p)
   547  {
   548  	free(p);
   549  }
   550  
   551  // hassuffix reports whether p ends with suffix.
   552  bool
   553  hassuffix(char *p, char *suffix)
   554  {
   555  	int np, ns;
   556  
   557  	np = strlen(p);
   558  	ns = strlen(suffix);
   559  	return np >= ns && streq(p+np-ns, suffix);
   560  }
   561  
   562  // hasprefix reports whether p begins with prefix.
   563  bool
   564  hasprefix(char *p, char *prefix)
   565  {
   566  	return strncmp(p, prefix, strlen(prefix)) == 0;
   567  }
   568  
   569  // contains reports whether sep appears in p.
   570  bool
   571  contains(char *p, char *sep)
   572  {
   573  	return strstr(p, sep) != nil;
   574  }
   575  
   576  // streq reports whether p and q are the same string.
   577  bool
   578  streq(char *p, char *q)
   579  {
   580  	return strcmp(p, q) == 0;
   581  }
   582  
   583  // lastelem returns the final path element in p.
   584  char*
   585  lastelem(char *p)
   586  {
   587  	char *out;
   588  
   589  	out = p;
   590  	for(; *p; p++)
   591  		if(*p == '/')
   592  			out = p+1;
   593  	return out;
   594  }
   595  
   596  // xmemmove copies n bytes from src to dst.
   597  void
   598  xmemmove(void *dst, void *src, int n)
   599  {
   600  	memmove(dst, src, n);
   601  }
   602  
   603  // xmemcmp compares the n-byte regions starting at a and at b.
   604  int
   605  xmemcmp(void *a, void *b, int n)
   606  {
   607  	return memcmp(a, b, n);
   608  }
   609  
   610  // xstrlen returns the length of the NUL-terminated string at p.
   611  int
   612  xstrlen(char *p)
   613  {
   614  	return strlen(p);
   615  }
   616  
   617  // xexit exits the process with return code n.
   618  void
   619  xexit(int n)
   620  {
   621  	exit(n);
   622  }
   623  
   624  // xatexit schedules the exit-handler f to be run when the program exits.
   625  void
   626  xatexit(void (*f)(void))
   627  {
   628  	atexit(f);
   629  }
   630  
   631  // xprintf prints a message to standard output.
   632  void
   633  xprintf(char *fmt, ...)
   634  {
   635  	va_list arg;
   636  	
   637  	va_start(arg, fmt);
   638  	vprintf(fmt, arg);
   639  	va_end(arg);
   640  }
   641  
   642  // errprintf prints a message to standard output.
   643  void
   644  errprintf(char *fmt, ...)
   645  {
   646  	va_list arg;
   647  	
   648  	va_start(arg, fmt);
   649  	vfprintf(stderr, fmt, arg);
   650  	va_end(arg);
   651  }
   652  
   653  // xsetenv sets the environment variable $name to the given value.
   654  void
   655  xsetenv(char *name, char *value)
   656  {
   657  	setenv(name, value, 1);
   658  }
   659  
   660  // main takes care of OS-specific startup and dispatches to xmain.
   661  int
   662  main(int argc, char **argv)
   663  {
   664  	Buf b;
   665  	int osx;
   666  	struct utsname u;
   667  
   668  	setvbuf(stdout, nil, _IOLBF, 0);
   669  	setvbuf(stderr, nil, _IOLBF, 0);
   670  
   671  	setenv("TERM", "dumb", 1); // disable escape codes in clang errors
   672  
   673  	binit(&b);
   674  	
   675  	slash = "/";
   676  
   677  #if defined(__APPLE__)
   678  	gohostos = "darwin";
   679  	// Even on 64-bit platform, darwin uname -m prints i386.
   680  	run(&b, nil, 0, "sysctl", "machdep.cpu.extfeatures", nil);
   681  	if(contains(bstr(&b), "EM64T"))
   682  		gohostarch = "amd64";
   683  #elif defined(__linux__)
   684  	gohostos = "linux";
   685  #elif defined(__DragonFly__)
   686  	gohostos = "dragonfly";
   687  #elif defined(__FreeBSD__)
   688  	gohostos = "freebsd";
   689  #elif defined(__FreeBSD_kernel__)
   690  	// detect debian/kFreeBSD. 
   691  	// http://wiki.debian.org/Debian_GNU/kFreeBSD_FAQ#Q._How_do_I_detect_kfreebsd_with_preprocessor_directives_in_a_C_program.3F
   692  	gohostos = "freebsd";	
   693  #elif defined(__OpenBSD__)
   694  	gohostos = "openbsd";
   695  #elif defined(__NetBSD__)
   696  	gohostos = "netbsd";
   697  #elif defined(__sun) && defined(__SVR4)
   698  	gohostos = "solaris";
   699  	// Even on 64-bit platform, solaris uname -m prints i86pc.
   700  	run(&b, nil, 0, "isainfo", "-n", nil);
   701  	if(contains(bstr(&b), "amd64"))
   702  		gohostarch = "amd64";
   703  	if(contains(bstr(&b), "i386"))
   704  		gohostarch = "386";
   705  #else
   706  	fatal("unknown operating system");
   707  #endif
   708  
   709  	if(gohostarch == nil) {
   710  		if(uname(&u) < 0)
   711  			fatal("uname: %s", strerror(errno));
   712  		if(contains(u.machine, "x86_64") || contains(u.machine, "amd64"))
   713  			gohostarch = "amd64";
   714  		else if(hassuffix(u.machine, "86"))
   715  			gohostarch = "386";
   716  		else if(contains(u.machine, "arm"))
   717  			gohostarch = "arm";
   718  		else
   719  			fatal("unknown architecture: %s", u.machine);
   720  	}
   721  
   722  	if(streq(gohostarch, "arm"))
   723  		maxnbg = 1;
   724  
   725  	// The OS X 10.6 linker does not support external linking mode.
   726  	// See golang.org/issue/5130.
   727  	//
   728  	// OS X 10.6 does not work with clang either, but OS X 10.9 requires it.
   729  	// It seems to work with OS X 10.8, so we default to clang for 10.8 and later.
   730  	// See golang.org/issue/5822.
   731  	//
   732  	// Roughly, OS X 10.N shows up as uname release (N+4),
   733  	// so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12.
   734  	if(streq(gohostos, "darwin")) {
   735  		if(uname(&u) < 0)
   736  			fatal("uname: %s", strerror(errno));
   737  		osx = atoi(u.release) - 4;
   738  		if(osx <= 6)
   739  			goextlinkenabled = "0";
   740  		if(osx >= 8)
   741  			defaultclang = 1;
   742  	}
   743  
   744  	init();
   745  	xmain(argc, argv);
   746  	bfree(&b);
   747  	return 0;
   748  }
   749  
   750  // xqsort is a wrapper for the C standard qsort.
   751  void
   752  xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
   753  {
   754  	qsort(data, n, elemsize, cmp);
   755  }
   756  
   757  // xstrcmp compares the NUL-terminated strings a and b.
   758  int
   759  xstrcmp(char *a, char *b)
   760  {
   761  	return strcmp(a, b);
   762  }
   763  
   764  // xstrstr returns a pointer to the first occurrence of b in a.
   765  char*
   766  xstrstr(char *a, char *b)
   767  {
   768  	return strstr(a, b);
   769  }
   770  
   771  // xstrrchr returns a pointer to the final occurrence of c in p.
   772  char*
   773  xstrrchr(char *p, int c)
   774  {
   775  	return strrchr(p, c);
   776  }
   777  
   778  // xsamefile reports whether f1 and f2 are the same file (or dir)
   779  int
   780  xsamefile(char *f1, char *f2)
   781  {
   782  	return streq(f1, f2); // suffice for now
   783  }
   784  
   785  sigjmp_buf sigill_jmpbuf;
   786  static void sigillhand(int);
   787  
   788  // xtryexecfunc tries to execute function f, if any illegal instruction
   789  // signal received in the course of executing that function, it will
   790  // return 0, otherwise it will return 1.
   791  // Some systems (notably NetBSD) will spin and spin when executing VFPv3
   792  // instructions on VFPv2 system (e.g. Raspberry Pi) without ever triggering
   793  // SIGILL, so we set a 1-second alarm to catch that case.
   794  int
   795  xtryexecfunc(void (*f)(void))
   796  {
   797  	int r;
   798  	r = 0;
   799  	signal(SIGILL, sigillhand);
   800  	signal(SIGALRM, sigillhand);
   801  	alarm(1);
   802  	if(sigsetjmp(sigill_jmpbuf, 1) == 0) {
   803  		f();
   804  		r = 1;
   805  	}
   806  	signal(SIGILL, SIG_DFL);
   807  	alarm(0);
   808  	signal(SIGALRM, SIG_DFL);
   809  	return r;
   810  }
   811  
   812  // SIGILL handler helper
   813  static void
   814  sigillhand(int signum)
   815  {
   816  	USED(signum);
   817  	siglongjmp(sigill_jmpbuf, 1);
   818  }
   819  
   820  static void
   821  __cpuid(int dst[4], int ax)
   822  {
   823  #ifdef __i386__
   824  	// we need to avoid ebx on i386 (esp. when -fPIC).
   825  	asm volatile(
   826  		"mov %%ebx, %%edi\n\t"
   827  		"cpuid\n\t"
   828  		"xchgl %%ebx, %%edi"
   829  		: "=a" (dst[0]), "=D" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
   830  		: "0" (ax));
   831  #elif defined(__x86_64__)
   832  	asm volatile("cpuid"
   833  		: "=a" (dst[0]), "=b" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
   834  		: "0" (ax));
   835  #else
   836  	dst[0] = dst[1] = dst[2] = dst[3] = 0;
   837  #endif
   838  }
   839  
   840  bool
   841  cansse2(void)
   842  {
   843  	int info[4];
   844  	
   845  	__cpuid(info, 1);
   846  	return (info[3] & (1<<26)) != 0;	// SSE2
   847  }
   848  
   849  #endif // PLAN9
   850  #endif // __WINDOWS__