rust/src/rt/rust_builtin.c
2015-02-11 14:49:11 -08:00

538 lines
10 KiB
C

// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#include <stdint.h>
#include <time.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#if !defined(__WIN32__)
#include <sys/time.h>
#include <sys/types.h>
#include <dirent.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#else
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <tchar.h>
#endif
#ifdef __APPLE__
#include <TargetConditionals.h>
#include <mach/mach_time.h>
#if !(TARGET_OS_IPHONE)
#include <crt_externs.h>
#endif
#endif
/* Foreign builtins. */
//include valgrind.h after stdint.h so that uintptr_t is defined for msys2 w64
#include "valgrind/valgrind.h"
#ifdef __APPLE__
#if (TARGET_OS_IPHONE)
extern char **environ;
#endif
#endif
#if defined(__FreeBSD__) || defined(__linux__) || defined(__ANDROID__) || \
defined(__DragonFly__) || defined(__Bitrig__) || defined(__OpenBSD__)
extern char **environ;
#endif
#if defined(__WIN32__)
char**
rust_env_pairs() {
return 0;
}
#else
char**
rust_env_pairs() {
#if defined(__APPLE__) && !(TARGET_OS_IPHONE)
char **environ = *_NSGetEnviron();
#endif
return environ;
}
#endif
char*
#if defined(__WIN32__)
rust_list_dir_val(WIN32_FIND_DATA* entry_ptr) {
return entry_ptr->cFileName;
}
#else
rust_list_dir_val(struct dirent* entry_ptr) {
return entry_ptr->d_name;
}
#endif
#ifndef _WIN32
DIR*
rust_opendir(char *dirname) {
return opendir(dirname);
}
int
rust_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
return readdir_r(dirp, entry, result);
}
int
rust_dirent_t_size() {
return sizeof(struct dirent);
}
#else
void
rust_opendir() {
}
void
rust_readdir() {
}
void
rust_dirent_t_size() {
}
#endif
uintptr_t
rust_running_on_valgrind() {
return RUNNING_ON_VALGRIND;
}
#if defined(__WIN32__)
int
get_num_cpus() {
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
return (int) sysinfo.dwNumberOfProcessors;
}
#elif defined(__BSD__)
int
get_num_cpus() {
/* swiped from http://stackoverflow.com/questions/150355/
programmatically-find-the-number-of-cores-on-a-machine */
unsigned int numCPU;
int mib[4];
size_t len = sizeof(numCPU);
/* set the mib for hw.ncpu */
mib[0] = CTL_HW;
mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU;
/* get the number of CPUs from the system */
sysctl(mib, 2, &numCPU, &len, NULL, 0);
if( numCPU < 1 ) {
mib[1] = HW_NCPU;
sysctl( mib, 2, &numCPU, &len, NULL, 0 );
if( numCPU < 1 ) {
numCPU = 1;
}
}
return numCPU;
}
#elif defined(__GNUC__)
int
get_num_cpus() {
return sysconf(_SC_NPROCESSORS_ONLN);
}
#endif
uintptr_t
rust_get_num_cpus() {
return get_num_cpus();
}
unsigned int
rust_valgrind_stack_register(void *start, void *end) {
return VALGRIND_STACK_REGISTER(start, end);
}
void
rust_valgrind_stack_deregister(unsigned int id) {
VALGRIND_STACK_DEREGISTER(id);
}
#if defined(__WIN32__)
void
rust_unset_sigprocmask() {
// empty stub for windows to keep linker happy
}
#else
void
rust_unset_sigprocmask() {
// this can't be safely converted to rust code because the
// representation of sigset_t is platform-dependent
sigset_t sset;
sigemptyset(&sset);
sigprocmask(SIG_SETMASK, &sset, NULL);
}
#endif
#if defined(__DragonFly__)
#include <errno.h>
// In DragonFly __error() is an inline function and as such
// no symbol exists for it.
int *__dfly_error(void) { return __error(); }
#endif
#if defined(__Bitrig__)
#include <stdio.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <limits.h>
int rust_get_path(void *p, size_t* sz)
{
int mib[4];
char *eq = NULL;
char *key = NULL;
char *val = NULL;
char **menv = NULL;
size_t maxlen, len;
int nenv = 0;
int i;
if ((p == NULL) && (sz == NULL))
return -1;
/* get the argv array */
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
mib[2] = getpid();
mib[3] = KERN_PROC_ENV;
/* get the number of bytes needed to get the env */
maxlen = 0;
if (sysctl(mib, 4, NULL, &maxlen, NULL, 0) == -1)
return -1;
/* allocate the buffer */
if ((menv = calloc(maxlen, sizeof(char))) == NULL)
return -1;
/* get the env array */
if (sysctl(mib, 4, menv, &maxlen, NULL, 0) == -1)
{
free(menv);
return -1;
}
mib[3] = KERN_PROC_NENV;
len = sizeof(int);
/* get the length of env array */
if (sysctl(mib, 4, &nenv, &len, NULL, 0) == -1)
{
free(menv);
return -1;
}
/* find _ key and resolve the value */
for (i = 0; i < nenv; i++)
{
if ((eq = strstr(menv[i], "=")) == NULL)
continue;
key = menv[i];
val = eq + 1;
*eq = '\0';
if (strncmp(key, "PATH", maxlen) != 0)
continue;
if (p == NULL)
{
/* return the length of the value + NUL */
*sz = strnlen(val, maxlen) + 1;
free(menv);
return 0;
}
else
{
/* copy *sz bytes to the output buffer */
memcpy(p, val, *sz);
free(menv);
return 0;
}
}
free(menv);
return -1;
}
int rust_get_path_array(void * p, size_t * sz)
{
char *path, *str;
char **buf;
int i, num;
size_t len;
if ((p == NULL) && (sz == NULL))
return -1;
/* get the length of the PATH value */
if (rust_get_path(NULL, &len) == -1)
return -1;
if (len == 0)
return -1;
/* allocate the buffer */
if ((path = calloc(len, sizeof(char))) == NULL)
return -1;
/* get the PATH value */
if (rust_get_path(path, &len) == -1)
{
free(path);
return -1;
}
/* count the number of parts in the PATH */
num = 1;
for(str = path; *str != '\0'; str++)
{
if (*str == ':')
num++;
}
/* calculate the size of the buffer for the 2D array */
len = (num * sizeof(char*) + 1) + strlen(path) + 1;
if (p == NULL)
{
free(path);
*sz = len;
return 0;
}
/* make sure we have enough buffer space */
if (*sz < len)
{
free(path);
return -1;
}
/* zero out the buffer */
buf = (char**)p;
memset(buf, 0, *sz);
/* copy the data into the right place */
str = p + ((num+1) * sizeof(char*));
memcpy(str, path, strlen(path));
/* parse the path into it's parts */
for (i = 0; i < num && (buf[i] = strsep(&str, ":")) != NULL; i++) {;}
buf[num] = NULL;
free(path);
return 0;
}
int rust_get_argv_zero(void* p, size_t* sz)
{
int mib[4];
char **argv = NULL;
size_t len;
if ((p == NULL) && (sz == NULL))
return -1;
/* get the argv array */
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
mib[2] = getpid();
mib[3] = KERN_PROC_ARGV;
/* request KERN_PROC_ARGV size */
len = 0;
if (sysctl(mib, 4, NULL, &len, NULL, 0) == -1)
return -1;
/* allocate buffer to receive the values */
if ((argv = malloc(len)) == NULL)
return -1;
/* get the argv array */
if (sysctl(mib, 4, argv, &len, NULL, 0) == -1)
{
free(argv);
return -1;
}
/* get length of argv[0] */
len = strnlen(argv[0], len) + 1;
if (p == NULL)
{
*sz = len;
free(argv);
return 0;
}
if (*sz < len)
{
free(argv);
return -1;
}
memset(p, 0, len);
memcpy(p, argv[0], len);
free(argv);
return 0;
}
const char * rust_current_exe()
{
static char *self = NULL;
char *argv0;
char **paths;
size_t sz;
int i;
char buf[2*PATH_MAX], exe[2*PATH_MAX];
if (self != NULL)
return self;
if (rust_get_argv_zero(NULL, &sz) == -1)
return NULL;
if ((argv0 = calloc(sz, sizeof(char))) == NULL)
return NULL;
if (rust_get_argv_zero(argv0, &sz) == -1)
{
free(argv0);
return NULL;
}
/* if argv0 is a relative or absolute path, resolve it with realpath */
if ((*argv0 == '.') || (*argv0 == '/') || (strstr(argv0, "/") != NULL))
{
self = realpath(argv0, NULL);
free(argv0);
return self;
}
/* get the path array */
if (rust_get_path_array(NULL, &sz) == -1)
{
free(argv0);
return NULL;
}
if ((paths = calloc(sz, sizeof(char))) == NULL)
{
free(argv0);
return NULL;
}
if (rust_get_path_array(paths, &sz) == -1)
{
free(argv0);
free(paths);
return NULL;
}
for(i = 0; paths[i] != NULL; i++)
{
snprintf(buf, 2*PATH_MAX, "%s/%s", paths[i], argv0);
if (realpath(buf, exe) == NULL)
continue;
if (access(exe, F_OK | X_OK) == -1)
continue;
self = strdup(exe);
free(argv0);
free(paths);
return self;
}
free(argv0);
free(paths);
return NULL;
}
#elif defined(__OpenBSD__)
#include <sys/param.h>
#include <sys/sysctl.h>
#include <limits.h>
const char * rust_current_exe() {
static char *self = NULL;
if (self == NULL) {
int mib[4];
char **argv = NULL;
size_t argv_len;
/* initialize mib */
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
mib[2] = getpid();
mib[3] = KERN_PROC_ARGV;
/* request KERN_PROC_ARGV size */
argv_len = 0;
if (sysctl(mib, 4, NULL, &argv_len, NULL, 0) == -1)
return (NULL);
/* allocate size */
if ((argv = malloc(argv_len)) == NULL)
return (NULL);
/* request KERN_PROC_ARGV */
if (sysctl(mib, 4, argv, &argv_len, NULL, 0) == -1) {
free(argv);
return (NULL);
}
/* get realpath if possible */
if ((argv[0] != NULL) && ((*argv[0] == '.') || (*argv[0] == '/')
|| (strstr(argv[0], "/") != NULL)))
self = realpath(argv[0], NULL);
else
self = NULL;
/* cleanup */
free(argv);
}
return (self);
}
#endif
//
// Local Variables:
// mode: C++
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//