diff options
Diffstat (limited to 'erts/emulator/test')
-rw-r--r-- | erts/emulator/test/trace_SUITE.erl | 69 | ||||
-rw-r--r-- | erts/emulator/test/trace_SUITE_data/Makefile.src | 5 | ||||
-rw-r--r-- | erts/emulator/test/trace_SUITE_data/slow_drv.c | 205 |
3 files changed, 279 insertions, 0 deletions
diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl index 221b65309a..caa58ae281 100644 --- a/erts/emulator/test/trace_SUITE.erl +++ b/erts/emulator/test/trace_SUITE.erl @@ -34,6 +34,7 @@ system_monitor_args/1, more_system_monitor_args/1, system_monitor_long_gc_1/1, system_monitor_long_gc_2/1, system_monitor_large_heap_1/1, system_monitor_large_heap_2/1, + system_monitor_long_schedule/1, bad_flag/1, trace_delivered/1]). -include_lib("test_server/include/test_server.hrl"). @@ -52,6 +53,7 @@ all() -> set_on_first_spawn, system_monitor_args, more_system_monitor_args, system_monitor_long_gc_1, system_monitor_long_gc_2, system_monitor_large_heap_1, + system_monitor_long_schedule, system_monitor_large_heap_2, bad_flag, trace_delivered]. groups() -> @@ -508,6 +510,65 @@ try_l(Val) -> ?line {Self,Comb1} = erlang:system_monitor(undefined), ?line [{large_heap,Val},{long_gc,Arbitrary2}] = lists:sort(Comb1). +monitor_sys(Parent) -> + receive + {monitor,Pid,long_schedule,Data} when is_pid(Pid) -> + io:format("Long schedule of ~w: ~w~n",[Pid,Data]), + Parent ! {Pid,Data}, + monitor_sys(Parent); + {monitor,Port,long_schedule,Data} when is_port(Port) -> + {name,Name} = erlang:port_info(Port,name), + io:format("Long schedule of ~w (~p): ~w~n",[Port,Name,Data]), + Parent ! {Port,Data}, + monitor_sys(Parent); + Other -> + erlang:display(Other) + end. + +start_monitor() -> + Parent = self(), + Mpid = spawn_link(fun() -> monitor_sys(Parent) end), + erlang:system_monitor(Mpid,[{long_schedule,100}]), + erlang:yield(), % Need to be rescheduled for the trace to take + ok. + +system_monitor_long_schedule(suite) -> + []; +system_monitor_long_schedule(doc) -> + ["Tests erlang:system_monitor(Pid, [{long_schedule,Time}])"]; +system_monitor_long_schedule(Config) when is_list(Config) -> + Path = ?config(data_dir, Config), + erl_ddll:start(), + case (catch load_driver(Path, slow_drv)) of + ok -> + do_system_monitor_long_schedule(); + _Error -> + {skip, "Unable to load slow_drv (windows or no usleep()?)"} + end. +do_system_monitor_long_schedule() -> + start_monitor(), + Port = open_port({spawn_driver,slow_drv}, []), + "ok" = erlang:port_control(Port,0,[]), + Self = self(), + receive + {Self,L} when is_list(L) -> + ok + after 1000 -> + ?t:fail(no_trace_of_pid) + end, + "ok" = erlang:port_control(Port,1,[]), + "ok" = erlang:port_control(Port,2,[]), + receive + {Port,LL} when is_list(LL) -> + ok + after 1000 -> + ?t:fail(no_trace_of_port) + end, + port_close(Port), + erlang:system_monitor(undefined), + ok. + + -define(LONG_GC_SLEEP, 670). system_monitor_long_gc_1(suite) -> @@ -1521,3 +1582,11 @@ issue_non_empty_runq_warning(DeadLine, RQLen) -> " Processes info: ~p~n", [DeadLine div 1000, RQLen, self(), PIs]), receive after 1000 -> ok end. + +load_driver(Dir, Driver) -> + case erl_ddll:load_driver(Dir, Driver) of + ok -> ok; + {error, Error} = Res -> + io:format("~s\n", [erl_ddll:format_error(Error)]), + Res + end. diff --git a/erts/emulator/test/trace_SUITE_data/Makefile.src b/erts/emulator/test/trace_SUITE_data/Makefile.src new file mode 100644 index 0000000000..4cd9249b8f --- /dev/null +++ b/erts/emulator/test/trace_SUITE_data/Makefile.src @@ -0,0 +1,5 @@ +DRVS = slow_drv@dll@ + +all: $(DRVS) + +@SHLIB_RULES@ diff --git a/erts/emulator/test/trace_SUITE_data/slow_drv.c b/erts/emulator/test/trace_SUITE_data/slow_drv.c new file mode 100644 index 0000000000..c3e9db0fb8 --- /dev/null +++ b/erts/emulator/test/trace_SUITE_data/slow_drv.c @@ -0,0 +1,205 @@ +/* ``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 + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved via the world wide web at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#ifndef UNIX +#if !defined(__WIN32__) && !defined(VXWORKS) +#define UNIX 1 +#endif +#endif + +/* We actually only want to run this on + Unix machines which have the usleep call */ +#if defined(UNIX) && !defined(HAVE_USLEEP) +#undef UNIX +#endif + +#ifdef UNIX +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> /* rand */ +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#ifdef HAVE_POLL_H +# include <poll.h> +#endif +#endif /* UNIX */ + +#include "erl_driver.h" + +static int slow_drv_init(void); +static void slow_drv_finish(void); +static ErlDrvData slow_drv_start(ErlDrvPort, char *); +static void slow_drv_stop(ErlDrvData); +static void slow_drv_ready_input(ErlDrvData, ErlDrvEvent); +static ErlDrvSSizeT slow_drv_control(ErlDrvData, unsigned int, + char *, ErlDrvSizeT, char **, ErlDrvSizeT); + +static ErlDrvEntry slow_drv_entry = { + slow_drv_init, + slow_drv_start, + slow_drv_stop, + NULL, /* output */ + slow_drv_ready_input, + NULL, /* ready_output */ + "slow_drv", + slow_drv_finish, + NULL, /* handle */ + slow_drv_control, + NULL, /* timeout */ + NULL, /* outputv */ + NULL, /* ready_async */ + NULL, /* flush */ + NULL, /* call */ + NULL, /* event */ + + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + ERL_DRV_FLAG_USE_PORT_LOCKING, + NULL,/* void *handle2 */ + NULL,/* process_exit */ + NULL /* stop select */ +}; +typedef struct { + ErlDrvPort port; + ErlDrvTermData id; + int test; + int s[2]; +} SlowDrvData; + +/* ------------------------------------------------------------------------- +** Entry functions +**/ + +DRIVER_INIT(slow_drv) +{ + return &slow_drv_entry; +} + + +static int +slow_drv_init(void) +{ + return 0; +} + +static void +slow_drv_finish(void) +{ +} + + +static ErlDrvData +slow_drv_start(ErlDrvPort port, char *command) +{ +#ifndef UNIX + return NULL; +#else + SlowDrvData *sddp = driver_alloc(sizeof(SlowDrvData)); + if (!sddp) { + errno = ENOMEM; + return ERL_DRV_ERROR_ERRNO; + } + sddp->port = port; + sddp->id = driver_mk_port(port); + sddp->test = 0; + sddp->s[0] = sddp->s[1] = -1; + return (ErlDrvData) sddp; +#endif +} + +static void +slow_drv_stop(ErlDrvData drv_data) { +#ifdef UNIX + SlowDrvData *sddp = (SlowDrvData *) drv_data; + + if (sddp->test) { + driver_select(sddp->port, (ErlDrvEvent) (ErlDrvSInt) sddp->s[0], DO_READ, 0); + close(sddp->s[0]); + close(sddp->s[1]); + } + + driver_free((void *) sddp); + +#endif +} + +static ErlDrvSSizeT +slow_drv_control(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) +{ + SlowDrvData *sddp = (SlowDrvData *) drv_data; + char *res_str = "ok"; + int res_len; + switch (command) { + case 0: + /* just be slow */ + usleep(222000); + break; + case 1: + /* create pipes and select on input */ + if (sddp->test) { + res_str = "no"; + break; + } + sddp->test = 1; + pipe(sddp->s); + driver_select(sddp->port, (ErlDrvEvent) (ErlDrvSInt) sddp->s[0], DO_READ, 1); + break; + case 2: + if (!sddp->test) { + res_str = "no"; + break; + } + write(sddp->s[1],"boo",3); + break; + } + + res_len = strlen(res_str); + if (res_len > rlen) { + char *abuf = driver_alloc(sizeof(char)*res_len); + if (!abuf) + return 0; + *rbuf = abuf; + } + + memcpy((void *) *rbuf, (void *) res_str, res_len); + + return res_len; +} + +static void +slow_drv_ready_input(ErlDrvData drv_data, ErlDrvEvent event) +{ +#ifdef UNIX + SlowDrvData *sddp = (SlowDrvData *) drv_data; + int fd = (int) (ErlDrvSInt) event; + if (sddp->test) { + char buff[3]; + usleep(212000); + read(sddp->s[0],buff,3); + driver_output(sddp->port, "TheEnd", 6); + } + +#endif +} |