Monthly Archives: March 2011

erl_ddll and dlopen

In Erlang we can use module erl_ddll to dynamically load a native driver library. The process is very complicated. It is implemented in these files:     otp_src_R14B01/erts/emulator/beam/erl_bif_ddll.c     otp_src_R14B01/erts/emulator/sys/unix/erl_unix_sys_ddll.c     otp_src_R14B01/erts/emulator/sys/win32/erl_win32_sys_ddll.c     … Both erl_unix_sys_dll.c and erl_win32_sys_ddll.c have implemented a common interface which is … Continue reading

Posted in erlang | Tagged , | Leave a comment

Another ehttpd Performance Test

1. The hello-world http server – ehttpd 2. Start ehttpd [root@localhost azunyanmoe]# ulimit -n 99999 [azunyanmoe@localhost ~]$ cat /proc/cpuinfo | grep GHz model name : Pentium(R) Dual-Core  CPU      E5500  @ 2.80GHz model name : Pentium(R) Dual-Core  CPU      E5500  @ 2.80GHz [azunyanmoe@localhost ~]$ free -m              total       used       free     shared    buffers     cached Mem:          1980       1276        703          0         34        635 -/+ buffers/cache:        606       1373 Swap:         4998         70       4928 [azunyanmoe@localhost ~]$ erlc ehttpd.erl [azunyanmoe@localhost ~]$ taskset -c 1 erl +K true +h 99999  +P 99999 -smp enable +S 2:1 -s ehttpd Erlang R14B01 (erts-5.8.2) [ source] [smp:2:1] [rq:2] [async-threads:0] [hipe] [kernel-poll:true] ehttpd ready with 2 schedulers on port 8888 Eshell V5.8.2  (abort with ^G) 1>  3. Run test with ab from another host azunyanmoe@localhost:~$ ab -c 60 -n 100000 http://192.168.1.100:8888/ This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 192.168.1.100 (be patient) Completed 10000 requests Completed 20000 requests Completed 30000 requests Completed 40000 requests Completed 50000 requests Completed 60000 requests Completed 70000 requests Completed 80000 requests Completed 90000 requests Completed 100000 requests Finished 100000 requests Server Software:         … Continue reading

Posted in erlang | Tagged , | Leave a comment

Erlang VM Opcodes

The Opcodes of Erlang’s emulator BEAM are listed as follow: -spec opname(1..152) -> {atom(),0..8}. opname(1) -> {label,1}; opname(2) -> {func_info,3}; opname(3) -> {int_code_end,0}; opname(4) -> {call,2}; opname(5) -> {call_last,3}; opname(6) -> {call_only,2}; opname(7) -> {call_ext,2}; opname(8) -> {call_ext_last,3}; opname(9) -> {bif0,2}; opname(10) -> {bif1,4}; opname(11) -> {bif2,5}; opname(12) -> {allocate,2}; opname(13) -> {allocate_heap,3}; opname(14) -> {allocate_zero,2}; opname(15) -> {allocate_heap_zero,3}; opname(16) -> {test_heap,2}; opname(17) -> {init,1}; opname(18) -> {deallocate,1}; opname(19) -> {return,0}; opname(20) -> {send,0}; opname(21) -> {remove_message,0}; opname(22) -> {timeout,0}; opname(23) -> {loop_rec,2}; opname(24) -> {loop_rec_end,1}; opname(25) -> {wait,1}; opname(26) -> {wait_timeout,2}; opname(27) -> {m_plus,4}; opname(28) -> {m_minus,4}; opname(29) -> {m_times,4}; opname(30) -> {m_div,4}; opname(31) -> {int_div,4}; opname(32) -> {int_rem,4}; opname(33) -> {int_band,4}; opname(34) -> {int_bor,4}; opname(35) -> {int_bxor,4}; opname(36) -> {int_bsl,4}; opname(37) -> {int_bsr,4}; opname(38) -> {int_bnot,3}; … Continue reading

Posted in erlang | Tagged | Leave a comment

Some details about erlang:open_port/2

erlang:open_port({spawn, Command}, …) erlang:open_port({spawn_executable, Command}, …) The following source code is from otp_src_R14B01/erts/emulator/sys/unix/sys.c /*  [arndt] In most Unix systems, including Solaris 2.5, ‘fork’ allocates memory  in swap space for the child of a ‘fork’, whereas ‘vfork’ does not do this.  The natural call to use here is therefore ‘vfork’. Due to a bug in  ‘vfork’ in Solaris 2.5 (apparently fixed in 2.6), using ‘vfork’  can be dangerous in what seems to be these circumstances:      If the child code under a vfork sets the signal action to SIG_DFL      (or SIG_IGN)      for any signal which was previously set to a signal handler, the      state of the parent is clobbered, so that the later arrival of      such a signal yields a sigsegv in the parent. If the signal was      not set to a signal handler, but ignored, all seems to work.  If you change the forking code below, beware of this. */ static ErlDrvDataspawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts){#define CMD_LINE_PREFIX_STR “exec “#define CMD_LINE_PREFIX_STR_SZ (sizeof(CMD_LINE_PREFIX_STR) – 1)     int ifd[2], ofd[2], len, pid, i;    char **volatile new_environ; /* volatile since a vfork() then cannot                                    cause ‘new_environ’ to be clobbered                                    in the parent process. */    int saved_errno;    long res;    char *cmd_line;#ifndef QNX    int unbind;#endif#if !DISABLE_VFORK    int no_vfork;    size_t no_vfork_sz = sizeof(no_vfork);     no_vfork = (erts_sys_getenv(“ERL_NO_VFORK”,                (char *) &no_vfork,                &no_vfork_sz) >= 0);#endif     switch (opts->read_write) {    case DO_READ:        if (pipe(ifd) < 0)            return ERL_DRV_ERROR_ERRNO;        if (ifd[0] >= max_files) {            close_pipes(ifd, ofd, opts->read_write);            errno = EMFILE;            return ERL_DRV_ERROR_ERRNO;        }        ofd[1] = -1;        /* keep purify happy */        break;    case DO_WRITE:        if (pipe(ofd) < 0)            return ERL_DRV_ERROR_ERRNO;        if (ofd[1] >= max_files) {            close_pipes(ifd, ofd, opts->read_write);            errno = EMFILE;            return ERL_DRV_ERROR_ERRNO;        }        ifd[0] = -1;        /* keep purify happy */        break;    case DO_READ|DO_WRITE:        if (pipe(ifd) < 0)            return ERL_DRV_ERROR_ERRNO;        errno = EMFILE;        /* default for next two conditions */        if (ifd[0] >= max_files || pipe(ofd) < 0) {            close_pipes(ifd, ofd, DO_READ);            return ERL_DRV_ERROR_ERRNO;        }        if (ofd[1] >= max_files) {            close_pipes(ifd, ofd, opts->read_write);            errno = EMFILE;            return ERL_DRV_ERROR_ERRNO;        }        break;    default:        ASSERT(0);        return ERL_DRV_ERROR_GENERAL;    }     if (opts->spawn_type == ERTS_SPAWN_EXECUTABLE) {        /* started with spawn_executable, not with spawn */        len = strlen(name);        cmd_line = (char *) erts_alloc_fnf(ERTS_ALC_T_TMP, len + 1);        if (!cmd_line) {            close_pipes(ifd, ofd, opts->read_write);            errno = ENOMEM;            return ERL_DRV_ERROR_ERRNO;        }        memcpy((void *) cmd_line,(void *) name, len);        cmd_line[len] = ”;        if (access(cmd_line,X_OK) != 0) {            int save_errno = errno;            erts_free(ERTS_ALC_T_TMP, cmd_line);            errno = save_errno;            return ERL_DRV_ERROR_ERRNO;        }    } else {        /* make the string suitable for giving to “sh” */        len = strlen(name);        cmd_line = (char *) erts_alloc_fnf(ERTS_ALC_T_TMP,                           CMD_LINE_PREFIX_STR_SZ + len + 1);        if (!cmd_line) {            close_pipes(ifd, ofd, opts->read_write);            errno = ENOMEM;            return ERL_DRV_ERROR_ERRNO;        }        memcpy((void *) cmd_line,               (void *) CMD_LINE_PREFIX_STR,               CMD_LINE_PREFIX_STR_SZ);        memcpy((void *) (cmd_line + CMD_LINE_PREFIX_STR_SZ),               (void *) name, len);        cmd_line[CMD_LINE_PREFIX_STR_SZ + len] = ”;    }     erts_smp_rwmtx_rlock(&environ_rwmtx);     if (opts->envir == NULL) {        new_environ = environ;    } else if ((new_environ = build_unix_environment(opts->envir)) == NULL) {        erts_smp_rwmtx_runlock(&environ_rwmtx);        erts_free(ERTS_ALC_T_TMP, (void *) cmd_line);        errno = ENOMEM;        return ERL_DRV_ERROR_ERRNO;    } #ifndef QNX    /* Block child from SIGINT and SIGUSR1. Must be before fork()       to be safe. */    block_signals();     CHLD_STAT_LOCK;     unbind = erts_sched_bind_atfork_prepare(); #if !DISABLE_VFORK    /* See fork/vfork discussion before this function. */    if (no_vfork) {#endif     DEBUGF((“Using fork\n”));    pid = fork();     if (pid == 0) {        /* The child! Setup child… */         if (erts_sched_bind_atfork_child(unbind) != 0)        goto child_error;         /* OBSERVE!         * Keep child setup after vfork() (implemented below and in         * erl_child_setup.c) up to date if changes are made here.         */         if (opts->use_stdio) {            if (opts->read_write & DO_READ) {                /* stdout for process */                if (dup2(ifd[1], 1) < 0)                    goto child_error;                if(opts->redir_stderr)                    /* stderr for process */                    if (dup2(ifd[1], 2) < 0)                        goto child_error;            }            if (opts->read_write & DO_WRITE)                /* stdin for process */                if (dup2(ofd[0], 0) < 0)                    goto child_error;        }        else {    /* XXX will fail if ofd[0] == 4 (unlikely..) */            if (opts->read_write & DO_READ)                if (dup2(ifd[1], 4) < 0)                    goto child_error;            if (opts->read_write & DO_WRITE)                if (dup2(ofd[0], 3) < 0)                    goto child_error;        }         for (i = opts->use_stdio ? 3 : 5; i < max_files; i++)            (void) close(i);         if (opts->wd && chdir(opts->wd) < 0)            goto child_error; #if defined(USE_SETPGRP_NOARGS)        /* SysV */        (void) setpgrp();#elif defined(USE_SETPGRP)        /* BSD */        (void) setpgrp(0, getpid());#else                    /* POSIX */        (void) setsid();#endif         unblock_signals();         if (opts->spawn_type == ERTS_SPAWN_EXECUTABLE) {            if (opts->argv == NULL) {                execle(cmd_line,cmd_line,(char *) NULL, new_environ);            } else {                if (opts->argv[0] == erts_default_arg0) {                    opts->argv[0] = cmd_line;                }                execve(cmd_line, opts->argv, new_environ);                if (opts->argv[0] == cmd_line) {                    opts->argv[0] = erts_default_arg0;                }            }        } else {            execle(“/bin/sh”,”sh”,”-c”,cmd_line,(char *)NULL,new_environ);        }    child_error:        _exit(1);    }     …}

Posted in erlang | Tagged | Leave a comment

Reading device files in Erlang

Reading device files in Erlang is not very straightforword. Most devices files cannot be opened with file:open/2 except /dev/null. 1> file:open(“/dev/urandom”, [read, raw]). {error,eisdir} 2> file:open(“/dev/zero”, [read, raw]). {error,eisdir} 3> file:open(“/dev/null”, [read, raw]). {ok,{file_descriptor,prim_file,{#Port<0.505>,7}}} What’s eisdir? The man page of … Continue reading

Posted in erlang | Tagged | Leave a comment

Hello world!

Welcome to WordPress.com. This is your first post. Edit or delete it and start blogging!

Posted in Uncategorized | 1 Comment