From 8047afd5a48434e2fb5819d52714a17ddf2b78a2 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Fri, 11 Mar 2011 18:11:18 +0100 Subject: Corrected fd_driver and cleaned up some really old code in win32/sys.[ch] --- erts/configure.in | 6 + erts/emulator/beam/sys.h | 4 +- erts/emulator/sys/win32/sys.c | 201 +++++++++++++++++------------- erts/etc/win32/nsis/dll_version_helper.sh | 73 ++++++++++- erts/etc/win32/nsis/find_redist.sh | 44 ++++--- 5 files changed, 219 insertions(+), 109 deletions(-) (limited to 'erts') diff --git a/erts/configure.in b/erts/configure.in index 627f734409..f81996676e 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -3659,6 +3659,12 @@ case "$erl_xcomp_without_sysroot-$with_ssl" in wrp="/machine/software/microsoft/windows/currentversion/" urp="uninstall/openssl_is1/inno setup: app path" rp="$wrp$urp" + if regtool -q get "$rp" > /dev/null; then + true + else + urp="uninstall/openssl (32-bit)_is1/inno setup: app path" + rp="$wrp$urp" + fi if regtool -q get "$rp" > /dev/null; then ssl_install_dir=`regtool -q get "$rp"` # Try hard to get rid of spaces... diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index ff828ae889..e64c43de6e 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -538,8 +538,8 @@ typedef struct preload { */ typedef struct _SysDriverOpts { - int ifd; /* Input file descriptor (fd driver). */ - int ofd; /* Outputfile descriptor (fd driver). */ + Uint ifd; /* Input file descriptor (fd driver). */ + Uint ofd; /* Outputfile descriptor (fd driver). */ int packet_bytes; /* Number of bytes in packet header. */ int read_write; /* Read and write bits. */ int use_stdio; /* Use standard I/O: TRUE or FALSE. */ diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c index 37041ed987..aa3bf7dd8d 100644 --- a/erts/emulator/sys/win32/sys.c +++ b/erts/emulator/sys/win32/sys.c @@ -75,7 +75,7 @@ static int create_pipe(LPHANDLE, LPHANDLE, BOOL, BOOL); static int application_type(const char* originalName, char fullPath[MAX_PATH], BOOL search_in_path, BOOL handle_quotes, int *error_return); -static int application_type_w(const char* originalName, WCHAR fullPath[MAX_PATH], +static int application_type_w(const WCHAR *originalName, WCHAR fullPath[MAX_PATH], BOOL search_in_path, BOOL handle_quotes, int *error_return); @@ -260,7 +260,7 @@ erts_sys_prepare_crash_dump(void) } static void -init_console() +init_console(void) { char* mode = erts_read_env("ERL_CONSOLE_MODE"); @@ -280,7 +280,7 @@ init_console() erts_free_read_env(mode); } -int sys_max_files() +int sys_max_files(void) { return max_files; } @@ -296,10 +296,7 @@ int sys_max_files() */ static int -get_and_remove_option(argc, argv, option) - int* argc; /* Number of arguments. */ - char* argv[]; /* The argument vector. */ - const char* option; /* Option to search for and remove. */ +get_and_remove_option(int* argc, char* argv[], const char *option) { int i; @@ -349,9 +346,7 @@ static char *get_and_remove_option2(int *argc, char **argv, char os_type[] = "win32"; void -os_flavor(namebuf, size) -char* namebuf; /* Where to return the name. */ -unsigned size; /* Size of name buffer. */ +os_flavor(char *namebuf, unsigned size) { switch (int_os_version.dwPlatformId) { case VER_PLATFORM_WIN32_WINDOWS: @@ -624,12 +619,7 @@ struct erl_drv_entry async_driver_entry = { */ static DriverData* -new_driver_data(port_num, packet_bytes, wait_objs_required, use_threads) - int port_num; /* The port number. */ - int packet_bytes; /* Number of bytes in header. */ - int wait_objs_required; /* The number objects this port is going - /* wait for (typically 1 or 2). */ - int use_threads; /* TRUE if threads are intended to be used. */ +new_driver_data(int port_num, int packet_bytes, int wait_objs_required, int use_threads) { DriverData* dp; @@ -867,12 +857,7 @@ threaded_handle_closer(LPVOID param) */ static ErlDrvData -set_driver_data(dp, ifd, ofd, read_write, report_exit) - DriverData* dp; - HANDLE ifd; - HANDLE ofd; - int read_write; - int report_exit; +set_driver_data(DriverData* dp, HANDLE ifd, HANDLE ofd, int read_write, int report_exit) { int index = dp - driver_data; int result; @@ -896,6 +881,31 @@ set_driver_data(dp, ifd, ofd, read_write, report_exit) return (ErlDrvData)index; } +static ErlDrvData +reuse_driver_data(DriverData *dp, HANDLE ifd, HANDLE ofd, int read_write, ErlDrvPort port_num) +{ + int index = dp - driver_data; + int result; + + dp->port_num = port_num; + dp->in.fd = ifd; + dp->out.fd = ofd; + dp->report_exit = 0; + + if (read_write & DO_READ) { + result = driver_select(dp->port_num, (ErlDrvEvent)dp->in.ov.hEvent, + ERL_DRV_READ|ERL_DRV_USE, 1); + ASSERT(result != -1); + } + + if (read_write & DO_WRITE) { + result = driver_select(dp->port_num, (ErlDrvEvent)dp->out.ov.hEvent, + ERL_DRV_WRITE|ERL_DRV_USE, 1); + ASSERT(result != -1); + } + return (ErlDrvData)index; +} + /* * Initialises an AsyncIo structure. */ @@ -969,10 +979,7 @@ release_async_io(AsyncIo* aio, ErlDrvPort port_num) */ static void -async_read_file(aio, buf, numToRead) - AsyncIo* aio; /* Pointer to driver data. */ - LPVOID buf; /* Pointer to buffer to receive data. */ - DWORD numToRead; /* Number of bytes to read. */ +async_read_file(AsyncIo* aio, LPVOID buf, DWORD numToRead) { aio->pendingError = NO_ERROR; #ifdef HARD_POLL_DEBUG @@ -1023,10 +1030,9 @@ async_read_file(aio, buf, numToRead) * ---------------------------------------------------------------------- */ static int -async_write_file(aio, buf, numToWrite) - AsyncIo* aio; /* Pointer to async control block. */ - LPVOID buf; /* Pointer to buffer with data to write. */ - DWORD numToWrite; /* Number of bytes to write. */ +async_write_file(AsyncIo* aio, /* Pointer to async control block. */ + LPVOID buf, /* Pointer to buffer with data to write. */ + DWORD numToWrite) /* Number of bytes to write. */ { aio->pendingError = NO_ERROR; if (aio->thread != (HANDLE) -1) { @@ -1070,12 +1076,12 @@ async_write_file(aio, buf, numToWrite) * ---------------------------------------------------------------------- */ static int -get_overlapped_result(aio, pBytesRead, wait) - AsyncIo* aio; /* Pointer to async control block. */ - LPDWORD pBytesRead; /* Where to place the number of bytes - * transferred. - */ - BOOL wait; /* If true, wait until result is ready. */ +get_overlapped_result(AsyncIo* aio, /* Pointer to async control block. */ + LPDWORD pBytesRead, /* Where to place the number of bytes + * transferred. + */ + BOOL wait /* If true, wait until result is ready. */ + ) { DWORD error = NO_ERROR; /* Error status from last function. */ @@ -1145,7 +1151,7 @@ fd_init(void) return 0; } static int -spawn_init() +spawn_init(void) { int i; #if defined(ERTS_SMP) && defined(USE_CANCELIOEX) @@ -1532,7 +1538,7 @@ create_child_process siStartInfo.hStdOutput = hStdout; siStartInfo.hStdError = hStderr; - applType = application_type_w(origcmd, (char *) execPath, FALSE, FALSE, + applType = application_type_w((WCHAR *) origcmd, execPath, FALSE, FALSE, errno_return); if (applType == APPL_NONE) { return FALSE; @@ -1555,7 +1561,7 @@ create_child_process if (run_cmd) { WCHAR cmdPath[MAX_PATH]; int cmdType; - cmdType = application_type_w((char *) L"cmd.exe", (char *) cmdPath, TRUE, FALSE, errno_return); + cmdType = application_type_w(L"cmd.exe", cmdPath, TRUE, FALSE, errno_return); if (cmdType == APPL_NONE || cmdType == APPL_DOS) { return FALSE; } @@ -1921,7 +1927,7 @@ static int application_type return applType; } -static int application_type_w (const char *originalName, /* Name of the application to find. */ +static int application_type_w (const WCHAR *originalName, /* Name of the application to find. */ WCHAR wfullpath[MAX_PATH],/* Filled with complete path to * application. */ BOOL search_in_path, /* If we should search the system wide path */ @@ -1937,25 +1943,24 @@ static int application_type_w (const char *originalName, /* Name of the applicat static WCHAR extensions[][5] = {L"", L".com", L".exe", L".bat"}; int is_quoted; int len; - WCHAR *wname = (WCHAR *) originalName; WCHAR xfullpath[MAX_PATH]; - len = wcslen(wname); - is_quoted = handle_quotes && len > 0 && wname[0] == L'"' && - wname[len-1] == L'"'; + len = wcslen(originalName); + is_quoted = handle_quotes && len > 0 && originalName[0] == L'"' && + originalName[len-1] == L'"'; applType = APPL_NONE; *error_return = ENOENT; for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) { if(is_quoted) { - lstrcpynW(xfullpath, wname+1, MAX_PATH - 7); /* Cannot start using StringCchCopy yet, we support + lstrcpynW(xfullpath, originalName+1, MAX_PATH - 7); /* Cannot start using StringCchCopy yet, we support older platforms */ len = wcslen(xfullpath); if(len > 0) { xfullpath[len-1] = L'\0'; } } else { - lstrcpynW(xfullpath, wname, MAX_PATH - 5); + lstrcpynW(xfullpath, originalName, MAX_PATH - 5); } wcscat(xfullpath, extensions[i]); /* It seems that the Unicode version does not allow in and out parameter to overlap. */ @@ -2080,9 +2085,10 @@ threaded_reader(LPVOID param) buf = OV_BUFFER_PTR(aio); numToRead = OV_NUM_TO_READ(aio); aio->pendingError = 0; - if (!ReadFile(aio->fd, buf, numToRead, &aio->bytesTransferred, NULL)) - aio->pendingError = GetLastError(); - else if (aio->flags & DF_XLAT_CR) { + if (!ReadFile(aio->fd, buf, numToRead, &aio->bytesTransferred, NULL)) { + int error = GetLastError(); + aio->pendingError = error; + } else if (aio->flags & DF_XLAT_CR) { char *s; int n; @@ -2209,56 +2215,79 @@ translate_fd(int fd) return handle; } +/* Driver level locking, start function is serialized */ +static DriverData *save_01_port = NULL; +static DriverData *save_22_port = NULL; + static ErlDrvData fd_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts) { DriverData* dp; int is_std_error = (opts->ofd == 2); - - opts->ifd = (int) translate_fd(opts->ifd); - opts->ofd = (int) translate_fd(opts->ofd); - if ((dp = new_driver_data(port_num, opts->packet_bytes, 2, TRUE)) == NULL) - return ERL_DRV_ERROR_GENERAL; - - if (!create_file_thread(&dp->in, DO_READ)) { - dp->port_num = PORT_FREE; - return ERL_DRV_ERROR_GENERAL; - } - - if (!create_file_thread(&dp->out, DO_WRITE)) { - dp->port_num = PORT_FREE; - return ERL_DRV_ERROR_GENERAL; - } - - fd_driver_input = &(dp->in); - dp->in.flags = DF_XLAT_CR; - if (is_std_error) { - dp->out.flags |= DF_DROP_IF_INVH; /* Just drop messages if stderror - is an invalid handle */ + int in = opts->ifd, out = opts->ofd; + + opts->ifd = (Uint) translate_fd(in); + opts->ofd = (Uint) translate_fd(out); + if ( in == 0 && out == 1 && save_01_port != NULL) { + dp = save_01_port; + return reuse_driver_data(dp, (HANDLE) opts->ifd, (HANDLE) opts->ofd, opts->read_write, port_num); + } else if (in == 2 && out == 2 && save_22_port != NULL) { + dp = save_22_port; + return reuse_driver_data(dp, (HANDLE) opts->ifd, (HANDLE) opts->ofd, opts->read_write, port_num); + } else { + if ((dp = new_driver_data(port_num, opts->packet_bytes, 2, TRUE)) == NULL) + return ERL_DRV_ERROR_GENERAL; + + if (!create_file_thread(&dp->in, DO_READ)) { + dp->port_num = PORT_FREE; + return ERL_DRV_ERROR_GENERAL; + } + + if (!create_file_thread(&dp->out, DO_WRITE)) { + dp->port_num = PORT_FREE; + return ERL_DRV_ERROR_GENERAL; + } + + fd_driver_input = &(dp->in); + dp->in.flags = DF_XLAT_CR; + if (is_std_error) { + dp->out.flags |= DF_DROP_IF_INVH; /* Just drop messages if stderror + is an invalid handle */ + } + + if ( in == 0 && out == 1) { + save_01_port = dp; + } else if (in == 2 && out == 2) { + save_22_port = dp; + } + return set_driver_data(dp, (HANDLE) opts->ifd, (HANDLE) opts->ofd, opts->read_write, 0); } - return set_driver_data(dp, opts->ifd, opts->ofd, opts->read_write, 0); } static void fd_stop(ErlDrvData d) { int fd = (int)d; + DriverData* dp = driver_data+fd; /* - * I don't know a clean way to terminate the threads - * (TerminateThread() doesn't release the stack), - * so will we'll let the threads live. Normally, the fd - * driver is only used to support the -oldshell option, - * so this shouldn't be a problem in practice. - * - * Since we will not attempt to terminate the threads, - * better not close the input or output files either. + * There's no way we can terminate an fd port in a consistent way. + * Instead we let it live until it's opened again (which it is, + * as the only FD-drivers are for 0,1 and 2 adn the only time they + * get closed is by init:reboot). + * So - just deselect them and let everything be as is. + * They get woken up in fd_start again, where the DriverData is + * remembered. /PaN */ + if (dp->in.ov.hEvent != NULL) { + (void) driver_select(dp->port_num, + (ErlDrvEvent)dp->in.ov.hEvent, + ERL_DRV_READ, 0); + } + if (dp->out.ov.hEvent != NULL) { + (void) driver_select(dp->port_num, + (ErlDrvEvent)dp->out.ov.hEvent, + ERL_DRV_WRITE, 0); + } - driver_data[fd].in.thread = (HANDLE) -1; - driver_data[fd].out.thread = (HANDLE) -1; - driver_data[fd].in.fd = INVALID_HANDLE_VALUE; - driver_data[fd].out.fd = INVALID_HANDLE_VALUE; - - /*return */ common_stop(fd); } static ErlDrvData @@ -2350,7 +2379,6 @@ threaded_exiter(LPVOID param) * because it is an auto reset event. Therefore, always set the * exit flag and signal the event. */ - i = 0; if (dp->out.thread != (HANDLE) -1) { dp->out.flags = DF_EXIT_THREAD; @@ -2718,6 +2746,7 @@ ready_input(ErlDrvData drv_data, ErlDrvEvent ready_event) driver_failure_eof(dp->port_num); } else { /* Report real errors. */ int error = GetLastError(); + (void) driver_select(dp->port_num, ready_event, ERL_DRV_READ, 0); _dosmaperr(error); driver_failure_posix(dp->port_num, errno); diff --git a/erts/etc/win32/nsis/dll_version_helper.sh b/erts/etc/win32/nsis/dll_version_helper.sh index 571ee3e39e..4eb092cc6f 100755 --- a/erts/etc/win32/nsis/dll_version_helper.sh +++ b/erts/etc/win32/nsis/dll_version_helper.sh @@ -26,6 +26,7 @@ # exit 0 cat > hello.c < #include int main(void) @@ -35,14 +36,74 @@ int main(void) } EOF -cl /MD hello.c > /dev/null 2>&1 +cl /MD hello.c > /dev/null 2>&1 if [ '!' -f hello.exe.manifest ]; then - echo "This compiler does not generate manifest files - OK if using mingw" >&2 - exit 0 + # Gah - VC 2010 changes the way it handles DLL's and manifests... Again... + # need another way of getting the version + DLLNAME=`dumpbin.exe /imports hello.exe | egrep MSVCR.*dll` + DLLNAME=`echo $DLLNAME` + cat > helper.c < +#include + +#define REQ_MODULE "$DLLNAME" + +int main(void) +{ + DWORD dummy; + DWORD versize; + int i,n; + unsigned char *versinfo; + char buff[100]; + + char *vs_verinfo; + unsigned int vs_ver_size; + + struct LANGANDCODEPAGE { + WORD language; + WORD codepage; + } *translate; + + unsigned int tr_size; + + if (!(versize = GetFileVersionInfoSize(REQ_MODULE,&dummy))) { + fprintf(stderr,"No version info size in %s!\n",REQ_MODULE); + exit(1); + } + versinfo=malloc(versize); + if (!GetFileVersionInfo(REQ_MODULE,dummy,versize,versinfo)) { + fprintf(stderr,"No version info in %s!\n",REQ_MODULE); + exit(2); + } + if (!VerQueryValue(versinfo,"\\\\VarFileInfo\\\\Translation",&translate,&tr_size)) { + fprintf(stderr,"No translation info in %s!\n",REQ_MODULE); + exit(3); + } + n = tr_size/sizeof(translate); + for(i=0; i < n; ++i) { + sprintf(buff,"\\\\StringFileInfo\\\\%04x%04x\\\\FileVersion", + translate[i].language,translate[i].codepage); + if (VerQueryValue(versinfo,buff,&vs_verinfo,&vs_ver_size)) { + printf("%s\n",(char *) vs_verinfo); + return 0; + } + } + fprintf(stderr,"Failed to find file version of %s\n",REQ_MODULE); + return 0; +} +EOF + cl /MD helper.c version.lib > /dev/null 2>&1 + if [ '!' -f helper.exe ]; then + echo "Failed to build helper program." >&2 + exit 1 + fi + NAME=$DLLNAME + VERSION=`./helper` +else + VERSION=`grep ' Date: Thu, 17 Mar 2011 15:49:45 +0100 Subject: Make erts_printf %T not recurse on C stack --- erts/emulator/beam/erl_printf_term.c | 452 ++++++++++++++++++++--------------- erts/emulator/beam/erl_process.c | 2 +- erts/emulator/test/bif_SUITE.erl | 29 ++- 3 files changed, 283 insertions(+), 200 deletions(-) (limited to 'erts') diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c index d9f132f067..b71404fd27 100644 --- a/erts/emulator/beam/erl_printf_term.c +++ b/erts/emulator/beam/erl_printf_term.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2005-2010. All Rights Reserved. + * Copyright Ericsson AB 2005-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -216,233 +216,289 @@ static int print_atom_name(fmtfn_t fn, void* arg, Eterm atom, long *dcount) } +#define PRT_BAR ((Eterm) 0) +#define PRT_COMMA ((Eterm) 1) +#define PRT_CLOSE_LIST ((Eterm) 2) +#define PRT_CLOSE_TUPLE ((Eterm) 3) +#define PRT_TERM ((Eterm) 4) +#define PRT_ONE_CONS ((Eterm) 5) +#define PRT_PATCH_FUN_SIZE ((Eterm) 6) +#define PRT_LAST_ARRAY_ELEMENT ((Eterm) 7) /* Note! Must be last... */ static int print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount) { + DECLARE_WSTACK(s); int res; int i; + Eterm val; Uint32 *ref_num; Eterm* nobj; +#if HALFWORD_HEAP + UWord wobj; +#endif res = 0; - if ((*dcount)-- <= 0) - return res; - -#ifdef HYBRID___NOT_ACTIVE - /* Color coded output based on memory location */ - if(ptr_val(obj) >= global_heap && ptr_val(obj) < global_hend) - PRINT_STRING(res, fn, arg, "\033[32m"); -#ifdef INCREMENTAL - else if(ptr_val(obj) >= inc_fromspc && ptr_val(obj) < inc_fromend) - PRINT_STRING(res, fn, arg, "\033[33m"); + goto L_jump_start; + + L_outer_loop: + while (!WSTACK_ISEMPTY(s)) { + switch (val = WSTACK_POP(s)) { + case PRT_COMMA: + PRINT_CHAR(res, fn, arg, ','); + goto L_outer_loop; + case PRT_BAR: + PRINT_CHAR(res, fn, arg, '|'); + goto L_outer_loop; + case PRT_CLOSE_LIST: + PRINT_CHAR(res, fn, arg, ']'); + goto L_outer_loop; + case PRT_CLOSE_TUPLE: + PRINT_CHAR(res, fn, arg, '}'); + goto L_outer_loop; + default: +#if HALFWORD_HEAP + obj = (Eterm) (wobj = WSTACK_POP(s)); +#else + obj = WSTACK_POP(s); #endif - else if(IS_CONST(obj)) - PRINT_STRING(res, fn, arg, "\033[34m"); - else - PRINT_STRING(res, fn, arg, "\033[31m"); + switch (val) { + case PRT_TERM: + break; + case PRT_ONE_CONS: + L_print_one_cons: + { + Eterm* cons = list_val(obj); + Eterm tl; + + obj = CAR(cons); + tl = CDR(cons); + if (is_not_nil(tl)) { + if (is_list(tl)) { + WSTACK_PUSH(s, tl); + WSTACK_PUSH(s, PRT_ONE_CONS); + WSTACK_PUSH(s, PRT_COMMA); + } else { + WSTACK_PUSH(s, tl); + WSTACK_PUSH(s, PRT_TERM); + WSTACK_PUSH(s, PRT_BAR); + } + } + } + break; + case PRT_LAST_ARRAY_ELEMENT: + { +#if HALFWORD_HEAP + Eterm* ptr = (Eterm *) wobj; +#else + Eterm* ptr = (Eterm *) obj; #endif + obj = *ptr; + } + break; + default: /* PRT_LAST_ARRAY_ELEMENT+1 and upwards */ + { +#if HALFWORD_HEAP + Eterm* ptr = (Eterm *) wobj; +#else + Eterm* ptr = (Eterm *) obj; +#endif + obj = *ptr++; + WSTACK_PUSH(s, (UWord) ptr); + WSTACK_PUSH(s, val-1); + WSTACK_PUSH(s, PRT_COMMA); + } + break; + } + break; + } - if (is_CP(obj)) { - PRINT_STRING(res, fn, arg, "'); - return res; - } + L_jump_start: - switch (tag_val_def(obj)) { - case NIL_DEF: - PRINT_STRING(res, fn, arg, "[]"); - break; - case ATOM_DEF: { - int tres = print_atom_name(fn, arg, obj, dcount); - if (tres < 0) - return tres; - res += tres; - if (*dcount <= 0) - return res; - break; - } - case SMALL_DEF: - PRINT_SLONG(res, fn, arg, 'd', 0, 1, (signed long) signed_val(obj)); - break; - case BIG_DEF: { - int print_res; - char def_buf[64]; - char *buf, *big_str; - Uint sz = (Uint) big_decimal_estimate(obj); - sz++; - if (sz <= 64) - buf = &def_buf[0]; - else - buf = erts_alloc(ERTS_ALC_T_TMP, sz); - big_str = erts_big_to_string(obj, buf, sz); - print_res = erts_printf_string(fn, arg, big_str); - if (buf != &def_buf[0]) - erts_free(ERTS_ALC_T_TMP, (void *) buf); - if (print_res < 0) - return print_res; - res += print_res; - break; - } - case REF_DEF: - case EXTERNAL_REF_DEF: - PRINT_STRING(res, fn, arg, "#Ref<"); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) ref_channel_no(obj)); - ref_num = ref_numbers(obj); - for (i = ref_no_of_numbers(obj)-1; i >= 0; i--) { - PRINT_CHAR(res, fn, arg, '.'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, (unsigned long) ref_num[i]); + if ((*dcount)-- <= 0) + goto L_done; + + if (is_CP(obj)) { + PRINT_STRING(res, fn, arg, "'); + goto L_done; } - PRINT_CHAR(res, fn, arg, '>'); - break; - case PID_DEF: - case EXTERNAL_PID_DEF: - PRINT_CHAR(res, fn, arg, '<'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) pid_channel_no(obj)); - PRINT_CHAR(res, fn, arg, '.'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) pid_number(obj)); - PRINT_CHAR(res, fn, arg, '.'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) pid_serial(obj)); - PRINT_CHAR(res, fn, arg, '>'); - break; - case PORT_DEF: - case EXTERNAL_PORT_DEF: - PRINT_STRING(res, fn, arg, "#Port<"); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) port_channel_no(obj)); - PRINT_CHAR(res, fn, arg, '.'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) port_number(obj)); - PRINT_CHAR(res, fn, arg, '>'); - break; - case LIST_DEF: - if (is_printable_string(obj)) { - int c; - PRINT_CHAR(res, fn, arg, '"'); - nobj = list_val(obj); - while (1) { - if ((*dcount)-- <= 0) - return res; - c = signed_val(*nobj++); - if (c == '\n') - PRINT_STRING(res, fn, arg, "\\n"); - else { - if (c == '"') - PRINT_CHAR(res, fn, arg, '\\'); - PRINT_CHAR(res, fn, arg, (char) c); - } - if (is_not_list(*nobj)) - break; - nobj = list_val(*nobj); - } - PRINT_CHAR(res, fn, arg, '"'); - } else { - PRINT_CHAR(res, fn, arg, '['); - nobj = list_val(obj); - while (1) { - int tres = print_term(fn, arg, *nobj++, dcount); - if (tres < 0) - return tres; - res += tres; - if (*dcount <= 0) - return res; - if (is_not_list(*nobj)) - break; - PRINT_CHAR(res, fn, arg, ','); - nobj = list_val(*nobj); - } - if (is_not_nil(*nobj)) { - int tres; - PRINT_CHAR(res, fn, arg, '|'); - tres = print_term(fn, arg, *nobj, dcount); - if (tres < 0) - return tres; - res += tres; - if (*dcount <= 0) - return res; + + switch (tag_val_def(obj)) { + case NIL_DEF: + PRINT_STRING(res, fn, arg, "[]"); + break; + case ATOM_DEF: { + int tres = print_atom_name(fn, arg, obj, dcount); + if (tres < 0) { + res = tres; + goto L_done; } - PRINT_CHAR(res, fn, arg, ']'); - } - break; - case TUPLE_DEF: - nobj = tuple_val(obj); /* pointer to arity */ - i = arityval(*nobj); /* arity */ - PRINT_CHAR(res, fn, arg, '{'); - while (i--) { - int tres = print_term(fn, arg, *++nobj, dcount); - if (tres < 0) - return tres; res += tres; if (*dcount <= 0) - return res; - if (i >= 1) - PRINT_CHAR(res, fn, arg, ','); - } - PRINT_CHAR(res, fn, arg, '}'); - break; - case FLOAT_DEF: { - FloatDef ff; - GET_DOUBLE(obj, ff); - PRINT_DOUBLE(res, fn, arg, 'e', 6, 0, ff.fd); + goto L_done; + break; } - break; - case BINARY_DEF: - { - ProcBin* pb = (ProcBin *) binary_val(obj); - if (pb->size == 1) - PRINT_STRING(res, fn, arg, "<<1 byte>>"); - else { - PRINT_STRING(res, fn, arg, "<<"); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, (unsigned long) pb->size); - PRINT_STRING(res, fn, arg, " bytes>>"); + case SMALL_DEF: + PRINT_SLONG(res, fn, arg, 'd', 0, 1, (signed long) signed_val(obj)); + break; + case BIG_DEF: { + int print_res; + char def_buf[64]; + char *buf, *big_str; + Uint sz = (Uint) big_decimal_estimate(obj); + sz++; + if (sz <= 64) + buf = &def_buf[0]; + else + buf = erts_alloc(ERTS_ALC_T_TMP, sz); + big_str = erts_big_to_string(obj, buf, sz); + print_res = erts_printf_string(fn, arg, big_str); + if (buf != &def_buf[0]) + erts_free(ERTS_ALC_T_TMP, (void *) buf); + if (print_res < 0) { + res = print_res; + goto L_done; } + res += print_res; + break; } - break; - case EXPORT_DEF: - { - Export* ep = *((Export **) (export_val(obj) + 1)); - Atom* module = atom_tab(atom_val(ep->code[0])); - Atom* name = atom_tab(atom_val(ep->code[1])); - - PRINT_STRING(res, fn, arg, "#Fun<"); - PRINT_BUF(res, fn, arg, module->name, module->len); + case REF_DEF: + case EXTERNAL_REF_DEF: + PRINT_STRING(res, fn, arg, "#Ref<"); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, + (unsigned long) ref_channel_no(obj)); + ref_num = ref_numbers(obj); + for (i = ref_no_of_numbers(obj)-1; i >= 0; i--) { + PRINT_CHAR(res, fn, arg, '.'); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, (unsigned long) ref_num[i]); + } + PRINT_CHAR(res, fn, arg, '>'); + break; + case PID_DEF: + case EXTERNAL_PID_DEF: + PRINT_CHAR(res, fn, arg, '<'); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, + (unsigned long) pid_channel_no(obj)); PRINT_CHAR(res, fn, arg, '.'); - PRINT_BUF(res, fn, arg, name->name, name->len); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, + (unsigned long) pid_number(obj)); PRINT_CHAR(res, fn, arg, '.'); - PRINT_SLONG(res, fn, arg, 'd', 0, 1, - (signed long) ep->code[2]); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, + (unsigned long) pid_serial(obj)); PRINT_CHAR(res, fn, arg, '>'); - } - break; - case FUN_DEF: - { - ErlFunThing *funp = (ErlFunThing *) fun_val(obj); - Atom *ap = atom_tab(atom_val(funp->fe->module)); - - PRINT_STRING(res, fn, arg, "#Fun<"); - PRINT_BUF(res, fn, arg, ap->name, ap->len); - PRINT_CHAR(res, fn, arg, '.'); - PRINT_SLONG(res, fn, arg, 'd', 0, 1, - (signed long) funp->fe->old_index); + break; + case PORT_DEF: + case EXTERNAL_PORT_DEF: + PRINT_STRING(res, fn, arg, "#Port<"); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, + (unsigned long) port_channel_no(obj)); PRINT_CHAR(res, fn, arg, '.'); - PRINT_SLONG(res, fn, arg, 'd', 0, 1, - (signed long) funp->fe->old_uniq); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, + (unsigned long) port_number(obj)); PRINT_CHAR(res, fn, arg, '>'); + break; + case LIST_DEF: + if (is_printable_string(obj)) { + int c; + PRINT_CHAR(res, fn, arg, '"'); + nobj = list_val(obj); + while (1) { + if ((*dcount)-- <= 0) + goto L_done; + c = signed_val(*nobj++); + if (c == '\n') + PRINT_STRING(res, fn, arg, "\\n"); + else { + if (c == '"') + PRINT_CHAR(res, fn, arg, '\\'); + PRINT_CHAR(res, fn, arg, (char) c); + } + if (is_not_list(*nobj)) + break; + nobj = list_val(*nobj); + } + PRINT_CHAR(res, fn, arg, '"'); + } else { + PRINT_CHAR(res, fn, arg, '['); + WSTACK_PUSH(s,PRT_CLOSE_LIST); + goto L_print_one_cons; + } + break; + case TUPLE_DEF: + nobj = tuple_val(obj); /* pointer to arity */ + i = arityval(*nobj); /* arity */ + PRINT_CHAR(res, fn, arg, '{'); + WSTACK_PUSH(s,PRT_CLOSE_TUPLE); + ++nobj; + if (i > 0) { + WSTACK_PUSH(s, (UWord) nobj); + WSTACK_PUSH(s, PRT_LAST_ARRAY_ELEMENT+i-1); + } + break; + case FLOAT_DEF: { + FloatDef ff; + GET_DOUBLE(obj, ff); + PRINT_DOUBLE(res, fn, arg, 'e', 6, 0, ff.fd); + } + break; + case BINARY_DEF: + { + ProcBin* pb = (ProcBin *) binary_val(obj); + if (pb->size == 1) + PRINT_STRING(res, fn, arg, "<<1 byte>>"); + else { + PRINT_STRING(res, fn, arg, "<<"); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, (unsigned long) pb->size); + PRINT_STRING(res, fn, arg, " bytes>>"); + } + } + break; + case EXPORT_DEF: + { + Export* ep = *((Export **) (export_val(obj) + 1)); + Atom* module = atom_tab(atom_val(ep->code[0])); + Atom* name = atom_tab(atom_val(ep->code[1])); + + PRINT_STRING(res, fn, arg, "#Fun<"); + PRINT_BUF(res, fn, arg, module->name, module->len); + PRINT_CHAR(res, fn, arg, '.'); + PRINT_BUF(res, fn, arg, name->name, name->len); + PRINT_CHAR(res, fn, arg, '.'); + PRINT_SLONG(res, fn, arg, 'd', 0, 1, + (signed long) ep->code[2]); + PRINT_CHAR(res, fn, arg, '>'); + } + break; + case FUN_DEF: + { + ErlFunThing *funp = (ErlFunThing *) fun_val(obj); + Atom *ap = atom_tab(atom_val(funp->fe->module)); + + PRINT_STRING(res, fn, arg, "#Fun<"); + PRINT_BUF(res, fn, arg, ap->name, ap->len); + PRINT_CHAR(res, fn, arg, '.'); + PRINT_SLONG(res, fn, arg, 'd', 0, 1, + (signed long) funp->fe->old_index); + PRINT_CHAR(res, fn, arg, '.'); + PRINT_SLONG(res, fn, arg, 'd', 0, 1, + (signed long) funp->fe->old_uniq); + PRINT_CHAR(res, fn, arg, '>'); + } + break; + default: + PRINT_STRING(res, fn, arg, "'); + break; } - break; - default: - PRINT_STRING(res, fn, arg, "'); - break; } + L_done: + + DESTROY_WSTACK(s); return res; } diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 4d6e982325..a510c467ed 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -7703,7 +7703,7 @@ erts_program_counter_info(int to, void *to_arg, Process *p) * only cause problems. */ for (i = 0; i < p->arity; i++) - erts_print(to, to_arg, " %T\n", p->arg_reg[i]); + erts_print(to, to_arg, " %.*T\n", INT_MAX, p->arg_reg[i]); } } } diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl index 016befdced..c7617d3b90 100644 --- a/erts/emulator/test/bif_SUITE.erl +++ b/erts/emulator/test/bif_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -24,6 +24,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, + display/1, display_huge/0, types/1, t_list_to_existing_atom/1,os_env/1,otp_7526/1, binary_to_atom/1,binary_to_existing_atom/1, @@ -33,6 +34,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [types, t_list_to_existing_atom, os_env, otp_7526, + display, atom_to_binary, binary_to_atom, binary_to_existing_atom, min_max]. @@ -60,6 +62,31 @@ end_per_testcase(_Func, Config) -> Dog=?config(watchdog, Config), ?t:timetrap_cancel(Dog). + +display(suite) -> + []; +display(doc) -> + ["Uses erlang:display to test that erts_printf does not do deep recursion"]; +display(Config) when is_list(Config) -> + Pa = filename:dirname(code:which(?MODULE)), + {ok, Node} = test_server:start_node(display_huge_term,peer, + [{args, "-pa "++Pa}]), + true = rpc:call(Node,?MODULE,display_huge,[]), + test_server:stop_node(Node), + ok. + +display_huge() -> + erlang:display(deeep(100000)). + +deeep(0,Acc) -> + Acc; +deeep(N,Acc) -> + deeep(N-1,[Acc|[]]). + +deeep(N) -> + deeep(N,[hello]). + + types(Config) when is_list(Config) -> c:l(erl_bif_types), case erlang:function_exported(erl_bif_types, module_info, 0) of -- cgit v1.2.3