From epm1@REDACTED Wed Mar 1 04:30:43 2000 From: epm1@REDACTED (Eric P. Melbardis) Date: Tue, 29 Feb 2000 19:30:43 -0800 Subject: vxWorks version Message-ID: <000a01bf832e$87899be0$010000c9@catfish> greetings, the erlang documentation alludes to a vxWorks port, also wind river mentions it on their web site how can one obtain this version? regards, eric melbardis. -------------- next part -------------- An HTML attachment was scrubbed... URL: From dgud@REDACTED Wed Mar 1 09:09:20 2000 From: dgud@REDACTED (Dan Gudmundsson) Date: Wed, 1 Mar 2000 09:09:20 +0100 (MET) Subject: How to add db node dynamicaly In-Reply-To: <38BC4D6A.138239EF@control.att.com> References: <38BC4D6A.138239EF@control.att.com> Message-ID: <14524.52818.821725.361840@rian> Start mnesia on the new node as a ram node (without a schema on disc) and invoke mnesia:change_config(extra_db_nodes, [a@REDACTED, b@REDACTED]) on the node. If you want a replica of a table on the new node, then you can call mnesia:add_table_copy(Table, node(), ram_copies). /Dan Vladimir Ulogov writes: > Hello folks, another mnesia question: > How to add new db node and populate database from the existing ones. As > sample, I'm having two database nodes and wants to add new one. Is any > standard way to add a new db node without stopping existing nodes? Is > any db syncronisation tools for mnesia (something more complicated and > flexible then just copying of the *.DAT files) > From etxuwig@REDACTED Wed Mar 1 09:44:00 2000 From: etxuwig@REDACTED (Ulf Wiger) Date: Wed, 1 Mar 2000 09:44:00 +0100 (MET) Subject: Erlang Versus Python Message-ID: <200003010844.JAA29122@etxb.ericsson.se> > Date: Tue, 29 Feb 2000 16:23:36 -0500 > From: Vladimir Ulogov > - Easy pipes. If I'm spawning some task using popen I'm having as much > instances as I'd spawn those tasks. In the Erlang open_port with the > same portname means the same port (please correct me if I'm wrong), > os:cmd(unix:cmd) also non-parallel if spawned from the different tasks. You are wrong about the open_port() semantics. Each call to open_port() leads to a new instance. os:cmd(Cmd) was serialized because open_port() used fork() to create the external process. This could be disastrous if the VM was very large, since fork() maps the same amount of memory to the child process. Nowadays, open_port() uses vfork(), which avoids this problem. In the near future, os:cmd/1 will also change back. /Uffe Ulf Wiger, Chief Designer AXD 301 Ericsson Telecom AB tfn: +46 8 719 81 95 Varuv?gen 9, ?lvsj? mob: +46 70 519 81 95 S-126 25 Stockholm, Sweden fax: +46 8 719 43 44 From sam@REDACTED Wed Mar 1 11:42:09 2000 From: sam@REDACTED (Samuel Tardieu) Date: Wed, 1 Mar 2000 11:42:09 +0100 Subject: How to add db node dynamicaly In-Reply-To: <14524.52818.821725.361840@rian>; from dgud@erix.ericsson.se on Wed, Mar 01, 2000 at 09:09:20AM +0100 References: <38BC4D6A.138239EF@control.att.com> <14524.52818.821725.361840@rian> Message-ID: <2000-03-01-11-42-09+trackit+sam@inf.enst.fr> | Start mnesia on the new node as a ram node (without a schema on disc) | and invoke mnesia:change_config(extra_db_nodes, [a@REDACTED, b@REDACTED]) on | the node. I just learned something, thanks. Maybe the doc should be state explicitely that this can be run on the new node (I may have missed it though). I thought that it could only be done on a node with the "real" mnesia started already, and I was using: rpc:call (a@REDACTED, mnesia, change_config, [extra_db_nodes, [node()]]) Sam From dgud@REDACTED Wed Mar 1 11:58:03 2000 From: dgud@REDACTED (Dan Gudmundsson) Date: Wed, 1 Mar 2000 11:58:03 +0100 (MET) Subject: How to add db node dynamicaly In-Reply-To: <2000-03-01-11-42-09+trackit+sam@inf.enst.fr> References: <38BC4D6A.138239EF@control.att.com> <14524.52818.821725.361840@rian> <2000-03-01-11-42-09+trackit+sam@inf.enst.fr> Message-ID: <14524.63223.678308.703109@rian> Samuel Tardieu writes: > | Start mnesia on the new node as a ram node (without a schema on disc) > | and invoke mnesia:change_config(extra_db_nodes, [a@REDACTED, b@REDACTED]) on > | the node. > > I just learned something, thanks. Maybe the doc should be state explicitely > that this can be run on the new node (I may have missed it though). > I thought that it could only be done on a node with the "real" mnesia > started already, and I was using: > > rpc:call (a@REDACTED, mnesia, change_config, [extra_db_nodes, [node()]]) > > Sam It can called on either the new node or on the already running nodes. /Dan From sam@REDACTED Wed Mar 1 11:38:39 2000 From: sam@REDACTED (Samuel Tardieu) Date: Wed, 1 Mar 2000 11:38:39 +0100 Subject: Erlang Versus Python In-Reply-To: <38BC38D8.756AA7BB@control.att.com>; from gandalf@control.att.com on Tue, Feb 29, 2000 at 04:23:36PM -0500 References: <200002280232.UAA08086@node-03.advancenet.net> <38B9EEE7.1F6CB7C6@ionet.net> <38BC38D8.756AA7BB@control.att.com> Message-ID: <2000-03-01-11-38-39+trackit+sam@inf.enst.fr> | - Python internally do not have any network support, the | CORBA/ILU/socket modules are system dependent, the no standard ways to | connect to Python worlds over net (it's a couple libraries on the net, | but none is a standard de-facto), the socket module presents on most | platforms but you are having raw socket interface a-la old-good Unix and | should take care about everything youself, Erlang - .... is; There is no much difference between Python and Erlang, sockets are accessed via a library, with a quite similar interface. Python: s = socket (AF_INET, SOCK_STREAM) s.connect (("remotemachine", remorteport)) s.send ("I am sending over the socket\n") Erlang: {ok, S} = gen_tcp:connect ("remotemachine", remoteport, []) gen_tcp:send (S, "I am sending over the socket\n") | - Easy access to the module internals (functions, classes, variables); Being an Ada fan (in addition to Python and Erlang), I'm happy to get some isolation. In Erlang and Ada, I can choose (using `export' and a spec respectively) what I export. In Python, I can only choose what I don't want to export and it adds an extra constraint (those names must either start with an underscore or some extra code must remove the binding for the functions I want to hide in the scope). | - On-fly compilation (if the source was changed, the python going to | recompile bytecode itself). This is really nice but dangerous feature, | if the updated module contains bugs, all system are going to crash; Just an extra note for people who do not know Python: Python does not recompile anything that has been compiled already. I mean, if you are editing a file and save it, the new version won't be reloaded in applications that are already referencing it unless `reload(module)' is used. As in Erlang, you can pre-load any needed module provided you built a list before (the "application" file in Erlang). | - Erlang: functional development environment, with nice network | capabilities, standard database and GUI, nice embedded possibilities for | distributed computation. Pretty difficult to extend on C/C++. You forgot "enhanced support for fault tolerance", which is quite important to me (you can't guess how many people got impressed by seeing the "application monitor" showing applications moving from one node to another; I have even been asked to do an "Erlang applied to fault tolerance" class for last-year students in ENST). I understand your concern about extensibility. In spite of its lower efficiency, I quite like the Erlang approach (ports or IC) which keeps the "dirty" parts (compiled code) from corrupting the virtual machine. If you trust the virtual machine interpreter for not crashing, and the standard supervisor and friends libraries for having been extensively tested, then you know that your application can last forever (ok, you have to trust a few other things such as the hardware and the OS if any). Sam From dgud@REDACTED Wed Mar 1 13:25:47 2000 From: dgud@REDACTED (Dan Gudmundsson) Date: Wed, 1 Mar 2000 13:25:47 +0100 (MET) Subject: Parttern matching in mnesia In-Reply-To: <38BC42CB.9587A504@control.att.com> References: <38BC42CB.9587A504@control.att.com> Message-ID: <14525.1175.890765.749351@rian> Vladimir Ulogov writes: > Hello folks, > Can somebody submit the samples for strings lookup in the mnesia table > which will perform similar to 'LIKE' operator in SQL. Another word, how > to construct operator like 'SELECT * FROM table WHERE str_field LIKE > "%abc%' (lookup all str_filed which _contain_ "abc") using > Mnesia/Mnemosyne > It's not possible to make a match like that in mnesia (or mnemosyne), you have to look at each record and do a search. You can find all records which have a key that begins with "asd" If you do mnesia:match_object({record_id, [$a, $s, $d | '_'], '_'}). Matching in mnesia is implemented with the functionality provided by (d)ets, see erl -man ets /Dan From gandalf@REDACTED Wed Mar 1 15:59:58 2000 From: gandalf@REDACTED (Vladimir Ulogov) Date: Wed, 01 Mar 2000 09:59:58 -0500 Subject: How to add db node dynamicaly References: <38BC4D6A.138239EF@control.att.com> <14524.52818.821725.361840@rian> <2000-03-01-11-42-09+trackit+sam@inf.enst.fr> Message-ID: <38BD306E.649334C5@control.att.com> Samuel Tardieu wrote: > rpc:call (a@REDACTED, mnesia, change_config, [extra_db_nodes, [node()]]) May be new function in the mnesia module, like mnesia:populate_node([nodes list]) will be useful and clean. > Sam -- %% Vladimir I. Ulogov (gandalf@REDACTED) AT&T Labs "Where lands meets water. Where earth meets air. Where body meets mind. Where space meets time. We like to be on one side, and look at the other." D.Adams "Mostly harmless" From luke@REDACTED Wed Mar 1 14:03:02 2000 From: luke@REDACTED (Luke Gorrie) Date: 01 Mar 2000 14:03:02 +0100 Subject: Erlang Versus Python In-Reply-To: Samuel Tardieu's message of "Wed, 1 Mar 2000 11:38:39 +0100" References: <200002280232.UAA08086@node-03.advancenet.net> <38B9EEE7.1F6CB7C6@ionet.net> <38BC38D8.756AA7BB@control.att.com> <2000-03-01-11-38-39+trackit+sam@inf.enst.fr> Message-ID: Samuel Tardieu writes: > There is no much difference between Python and Erlang, sockets are > accessed via a library, with a quite similar interface. > > Python: > > s = socket (AF_INET, SOCK_STREAM) > s.connect (("remotemachine", remorteport)) > s.send ("I am sending over the socket\n") > > Erlang: > > {ok, S} = gen_tcp:connect ("remotemachine", remoteport, []) > gen_tcp:send (S, "I am sending over the socket\n") But remember that Erlang also has rather transparent distribution using message passing. Maybe it says something about how nicely integrated that feature is, since it's not what you thought of when someone mentioned networking :-) Cheers, Luke From sam@REDACTED Wed Mar 1 14:07:14 2000 From: sam@REDACTED (Samuel Tardieu) Date: Wed, 1 Mar 2000 14:07:14 +0100 Subject: Erlang Versus Python In-Reply-To: ; from luke@bluetail.com on Wed, Mar 01, 2000 at 02:03:02PM +0100 References: <200002280232.UAA08086@node-03.advancenet.net> <38B9EEE7.1F6CB7C6@ionet.net> <38BC38D8.756AA7BB@control.att.com> <2000-03-01-11-38-39+trackit+sam@inf.enst.fr> Message-ID: <2000-03-01-14-07-14+trackit+sam@inf.enst.fr> Luke: | But remember that Erlang also has rather transparent distribution | using message passing. Maybe it says something about how nicely | integrated that feature is, since it's not what you thought of when | someone mentioned networking :-) I thought about it, but transparent distribution is not everything: people need to build applications that communicate with the outside world using sockets. From gandalf@REDACTED Wed Mar 1 15:57:05 2000 From: gandalf@REDACTED (Vladimir Ulogov) Date: Wed, 01 Mar 2000 09:57:05 -0500 Subject: Erlang Versus Python References: <200002280232.UAA08086@node-03.advancenet.net> <38B9EEE7.1F6CB7C6@ionet.net> <38BC38D8.756AA7BB@control.att.com> <2000-03-01-11-38-39+trackit+sam@inf.enst.fr> Message-ID: <38BD2FC1.908B58AC@control.att.com> Samuel Tardieu wrote: > There is no much difference between Python and Erlang, sockets are > accessed via a library, with a quite similar interface. Yes, the sockets are looks the same if we forget about the Python using socket handler, and ERlang using port. Due this difference, in the Python you should use methods of the socket instance, in the Erlang gen_tcp or io. But what I'd wants to say, in the Erlang the socket isn't part of the environment, which you can't take away, in Python - you can. > must either start with an underscore or some extra code must remove > the binding for the functions I want to hide in the scope). You can always use __ names which are private for specific class/module. >From the Python 1.5 the hierarhical tree of the modules was added, which doesn't exists in Erlang. Also, the most people do not operate with .__dict__ or .__class__ references in the Python module/object/class, but sometimes, it's pretty handy. > Just an extra note for people who do not know Python: > Python does not recompile anything that has been compiled already. I Agree, sorry for forget to mention it. The Python checks module __each time__ during the import. In the Erlang, if you wants to regenerate .beam, .jam files, you should use erlc and compilation stage are separated from execution. This affects the development cycle. In Python it's looks like: Change->Run->Change. In Erlang Change->Compile->[Run|Change]. > You forgot "enhanced support for fault tolerance", which is quite Mea culpa. > efficiency, I quite like the Erlang approach (ports or IC) which keeps > the "dirty" parts (compiled code) from corrupting the virtual machine. It's aways good to have both ways: IC/ports (CORBA/popen in Python) and integrating compiled code into machine. But if we will remember original posting, it wasn't discusses about "which is the best", but what's the difference. And in this term, this is the difference regardless it's best or worst approach. IMHO it's mostly depends from application. > Sam -- %% Vladimir I. Ulogov (gandalf@REDACTED) AT&T Labs "Where lands meets water. Where earth meets air. Where body meets mind. Where space meets time. We like to be on one side, and look at the other." D.Adams "Mostly harmless" From gandalf@REDACTED Wed Mar 1 16:04:23 2000 From: gandalf@REDACTED (Vladimir Ulogov) Date: Wed, 01 Mar 2000 10:04:23 -0500 Subject: Erlang Versus Python References: <200002280232.UAA08086@node-03.advancenet.net> <38B9EEE7.1F6CB7C6@ionet.net> <38BC38D8.756AA7BB@control.att.com> <2000-03-01-11-38-39+trackit+sam@inf.enst.fr> <2000-03-01-14-07-14+trackit+sam@inf.enst.fr> Message-ID: <38BD3177.C35B8454@control.att.com> Samuel Tardieu wrote: > I thought about it, but transparent distribution is not everything: people > need to build applications that communicate with the outside world using > sockets. Again, it wasn't a word about is it good or bad. I'd just note about the difference. Python - (socket/FNORB/ILU/rpc) , Erlang - (socket/CORBA/rpc/transparent distribution). And can I remind one more time, in the Python __only__ socket are part of the standard library (let assume the host platform supports sockets), in Erlang all these ways are more well integrated. Thats it. -- %% Vladimir I. Ulogov (gandalf@REDACTED) AT&T Labs "Where lands meets water. Where earth meets air. Where body meets mind. Where space meets time. We like to be on one side, and look at the other." D.Adams "Mostly harmless" From pan@REDACTED Wed Mar 1 17:18:08 2000 From: pan@REDACTED (Patrik Nyblom) Date: Wed, 01 Mar 2000 17:18:08 +0100 Subject: vxWorks version References: <000a01bf832e$87899be0$010000c9@catfish> Message-ID: <38BD42C0.59E9E68D@erix.ericsson.se> "Eric P. Melbardis" wrote: > greetings, the erlang documentation alludes to a vxWorks port, > alsowind river mentions it on their web site how can one obtain this > version? regards, eric melbardis. The VxWorks things are included in the open source package, it is however not obvious how to build it (or run it). Before you start, remember that erlang on VxWorks is not as user friendly as on Unix/NT. Especially the user interface is primitive. The PowerPC 603, the PowerQuicc 860 and Cpu32 (M68360) are supported, their respective target names are vxworks_ppc603, vxworks_ppc860 and vxworks_cpu32 The makefiles assume a Unix Box with tornado installed. I've not tried VxWorks 5.4 (or tornado for that, whatever that version number is), only 5.2/1.1 but I suppose it will work to compile with later versions. This is a step by step instruction (assuming your gnu make program is named gmake and the target is vxworks_ppc603) 1) Build and install the open source erlang and put it in your path. 2) Unpack a fresh source tree. say into /src/vx/otp_src_R6B-0 3) cd /src/vx/otp_src_R6B-0; ./configure --prefix= 4) Setup the tornado environment variables (like WIND_BASE etc) 5) setup the ERL_TOP environment variable (to /src/vx/otp_src_R6B-0) 6) mkdir $ERL_TOP/lib/erl_interface/bin; mkdir $ERL_TOP/lib/erl_interface/obj (sorry about this...) 7) cd $ERL_TOP/erts/autoconf; gmake TARGET=vxworks_ppc603 8) cd $ERL_TOP; gmake TARGET=vxworks_ppc603 emulator libs 9) gmake TARGET=vxworks_ppc603 install (ignore the error './Install - not found', there is no Install script for VxWorks) 10) cd /lib/erlang 11) mkdir bin; cp releases/R6B/*.boot ./bin/ 12) Examine the file /lib/erlang/README.VxWorks and /lib/erlang/erts-4.9.1/bin/erl_script.sam which is an example of the commands needed to set up the VxWorks node to start erlang. Especially note that the command line option -oldshell NEED to be present. Use the NFS file system to mount the place where erlang is installed from the VxWorks card. Do NOT use the rcp file sysntem, it's simply to slow. You can of course copy erlang to a local file system (flash/disk/whatever) on the target, but most people find it simpler to use the host's file system during development. 13) When erlang is started on the VxWorks host (the erlang prompt shows up on the console), log into the VxWorks card and run the command 'to_erl' to be able to type into the erlang shell. If you are using a host based shell, be sure to sychronize the symbol tablers and the file systems on the target and the host. A target based symbol table IS needed, you can not have only a host based. Preferrably log into the card with telnet or rlogin instead of using the host based thing.This is the old erlang shell with no editing possibilities and no prompt on continuing lines, type a '.' (full stop) followed by a return to get the prompt. You can use the distribution to access the node from another machine too (of course). Exit the erlang shell (or actually the to_erl program) with Ctrl-D. Good luck /Patrik From dne@REDACTED Wed Mar 1 23:27:47 2000 From: dne@REDACTED (Daniel Neri) Date: Wed, 01 Mar 2000 23:27:47 +0100 Subject: Efile_drv and non-regular files Message-ID: <877lfmqqak.fsf@nowhere.mayonnaise.net> Hi, I just happened to try the following, while playing around in the shell: ,---- | Erlang (BEAM) emulator version 4.9.1 [source] | | Eshell V4.9.1 (abort with ^G) | 1> {ok, F} = file:open("/dev/null", [read]). | ** exited: {{badmatch,{error,eisdir}},[{erl_eval,expr,3}]} ** `---- It turns out efile_drv tries to protect the user a wee bit too hard IMO, by making "open" on *any* non-regular file fail with "eisdir". Wouldn't it be better to leave the "protection business" to the underlying OS? Opening a special file might be valid in some cases. I propose removing the "regular file" check in efile_openfile (see patch below), thus allowing for: ,---- | 8> {ok, F} = file:open("/dev/urandom", [read]). | {ok,<0.38.0>} | 9> file:read(F, 10). | {ok,[133,127,43,164,72,146,120,246,240,80]} `---- But still not letting through the obvious error (which I assume was the reason for this check): ,---- | 10> {ok, T} = file:open("/tmp", [write]). | ** exited: {{badmatch,{error,eisdir}},[{erl_eval,expr,3}]} ** `---- At the least, use a less misleading error identifier... Best wishes, /Daniel -- Daniel Neri dne@REDACTED From dne@REDACTED Wed Mar 1 23:34:52 2000 From: dne@REDACTED (Daniel Neri) Date: Wed, 01 Mar 2000 23:34:52 +0100 Subject: Efile_drv and non-regular files In-Reply-To: Daniel Neri's message of "01 Mar 2000 23:27:47 +0100" References: <877lfmqqak.fsf@nowhere.mayonnaise.net> Message-ID: <871z5uqpyr.fsf@nowhere.mayonnaise.net> Of course, I forgot to include the patch... /Daniel -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: text/x-patch Size: 408 bytes Desc: efile_openfile patch URL: From jhague@REDACTED Thu Mar 2 03:12:08 2000 From: jhague@REDACTED (James Hague) Date: Wed, 1 Mar 00 20:12:08 -0600 Subject: Erlang AI? Message-ID: <200003020211.UAA13811@node-02.advancenet.net> Craig Dickson wrote: >> IMO Erlang is the best functional language for AI work, because of atoms >> and dynamic typing. > >Scheme has both those properties, plus the ability to manipulate code as >data, which I would think terribly useful for AI. Why is Erlang a better >language for AI than Scheme? (I suppose Erlang's concurrency might be >helpful.) Oh, that wasn't intended as a knock at Scheme at all. I don't lump Scheme into the same group as other modern functional languages--that is, languages with heavy reliance on pattern matching and not such an an easy fallback into imperative programming as "set!". From shrogers@REDACTED Thu Mar 2 03:18:08 2000 From: shrogers@REDACTED (Steven H. Rogers) Date: Wed, 01 Mar 2000 20:18:08 -0600 Subject: Erlang Versus Python References: <200002280232.UAA08086@node-03.advancenet.net> <38B9EEE7.1F6CB7C6@ionet.net> <38BC38D8.756AA7BB@control.att.com> Message-ID: <38BDCF60.81800E9F@ionet.net> Vladimir Ulogov wrote: > > In my humble opinion it is no way to compare Erlang and Python. Actually, I think you've done a good job of comparing (and contrasting) them, and I appreciate it. I do have a couple of points of contention. > This is absolutely different languages. The key points are: > - Python is OO dynamic language, Erlang - functional; Python has some functional features, though they're not as well integrated into the language as they could be. > - Distributed database in the standard Python distribution ... what are > you talking about, Erlang - having mnesia; I didn't say that a distributed as a standard part of Python. The fact that Erlang has Mnesia is an obvious point in it's favor. With Python I could use something like Gadfly or Interbase, but would have to take care of the distribution myself. Regards, Steve From pan@REDACTED Thu Mar 2 08:12:55 2000 From: pan@REDACTED (Patrik Nyblom) Date: Thu, 02 Mar 2000 08:12:55 +0100 Subject: Efile_drv and non-regular files References: <877lfmqqak.fsf@nowhere.mayonnaise.net> Message-ID: <38BE1477.FF216591@erix.ericsson.se> Hi, You are correct in that the error return value is misleading, there is however a very good reason not to allow opening of other files than regular ones; The efile driver expects the file to be regular in the sense that operations won't block (i.e. a "fast" device). If one could open e.g a tape drive and write to it, the whole erlang machine will block for several seconds/minutes/hours, which is not especially nice. If one wants to operate on special files, one have to either write a "port program" (which will spin in a separate process) or write a loadable driver, which uses threads or the io multiplexing mechanisms to avoid hanging the emulator. Note that the reason why the efile driver is written in this way is that one cannot io multiplex (i.e. use select/poll) on regular files in a meaningful way on lots of u*x'es. Using threads is inefficient and hard to port, so that idea is also dropped (regarding regular files). Of course one could allow opening of "fast" devices through the efile driver, but I know of no portable way of desciding if a file represents a "fast" device. Maybe an alternative "any-type-of-file-driver" which uses threads/separate processes would be nice though. /Patrik Daniel Neri wrote: > Hi, > > I just happened to try the following, while playing around in the > shell: > > ,---- > | Erlang (BEAM) emulator version 4.9.1 [source] > | > | Eshell V4.9.1 (abort with ^G) > | 1> {ok, F} = file:open("/dev/null", [read]). > | ** exited: {{badmatch,{error,eisdir}},[{erl_eval,expr,3}]} ** > `---- > > It turns out efile_drv tries to protect the user a wee bit too hard > IMO, by making "open" on *any* non-regular file fail with > "eisdir". Wouldn't it be better to leave the "protection business" to > the underlying OS? Opening a special file might be valid in some > cases. > > I propose removing the "regular file" check in efile_openfile (see > patch below), thus allowing for: > > ,---- > | 8> {ok, F} = file:open("/dev/urandom", [read]). > | {ok,<0.38.0>} > | 9> file:read(F, 10). > | {ok,[133,127,43,164,72,146,120,246,240,80]} > `---- > > But still not letting through the obvious error (which I assume was > the reason for this check): > > ,---- > | 10> {ok, T} = file:open("/tmp", [write]). > | ** exited: {{badmatch,{error,eisdir}},[{erl_eval,expr,3}]} ** > `---- > > At the least, use a less misleading error identifier... > > Best wishes, > /Daniel > > -- > Daniel Neri > dne@REDACTED From per@REDACTED Thu Mar 2 15:11:34 2000 From: per@REDACTED (Per Hedeland) Date: Thu, 2 Mar 2000 15:11:34 +0100 (MET) Subject: Mailing list archives Message-ID: <200003021411.e22EBYc22518@super.du.uab.ericsson.se> There are now HTMLized, searchable archives of this list available at: http://www.erlang.org/ml-archive/erlang-questions/ (also linked from the "FAQ" page). --Per Hedeland per@REDACTED From gandalf@REDACTED Thu Mar 2 17:08:13 2000 From: gandalf@REDACTED (Vladimir Ulogov) Date: Thu, 02 Mar 2000 11:08:13 -0500 Subject: Erlang Versus Python References: <200002280232.UAA08086@node-03.advancenet.net> <38B9EEE7.1F6CB7C6@ionet.net> <38BC38D8.756AA7BB@control.att.com> <38BDCF60.81800E9F@ionet.net> Message-ID: <38BE91ED.965AB818@control.att.com> "Steven H. Rogers" wrote: > Python has some functional features, though they're not as well > integrated into the language as they could be. Yes, it the terms of possibility to create functions, the answer will be :YES, oterwize, the arrpoach are different. Python do not support pattern matching, sample: a(A,B,C) -> none; a(A,B) -> noop; a(10, abc) -> abc. Will be three different functions in Erlang, In the Python you can't do this. If you'll tell: def a(a1, b1): return "none" def a(a2): return "noop" The second "a" will be substitute the first one. You can use the keyworks as parameters, like: def a(*params, **kw): params - tuple kw - dictionary .... a(a,b,c,d, e="hello", f="world") will looks: params=(a,b,c,d); kw={e:"hello","f:"world"}. But in this case, you should check the types and data youself. It's a possible to emulate Erlang like pattern matching by importing the different modules, but it's taff. In the terrms of functions, the Python staying close to the Unix shell scripting and probably Perl (but of course, it's more flexible through *params and *kw) > > you talking about, Erlang - having mnesia; It's a lot of opinions how mnesia good in some specific applications, but it's exists and doing things which actually very useful, like transparent network replications. > could use something like Gadfly or Interbase, but would have to take > care of the distribution myself. Some of Python databases can't do distributed replications at all (it's really depend from which database we gonna to use). > Steve -- %% Vladimir I. Ulogov (gandalf@REDACTED) AT&T Labs "Where lands meets water. Where earth meets air. Where body meets mind. Where space meets time. We like to be on one side, and look at the other." D.Adams "Mostly harmless" From sallach@REDACTED Thu Mar 2 19:55:39 2000 From: sallach@REDACTED (David Sallach) Date: Thu, 02 Mar 2000 12:55:39 -0600 Subject: Erlang AI? In-Reply-To: <004401bf82c5$b18ded60$6f01140a@inkpad> References: <200002290216.UAA27333@node-02.advancenet.net> Message-ID: <200003021856.MAA21319@allman.src.uchicago.edu> Given that Elrlang has much of the functionality of LISP, PROLOG, Scheme & other functional languages, its unique AI niche, seems to be its applicability to real world problems. It's concurrency and robustness are major aspects of this, but so is Mnesia with its extended relational model, lack of an impedence mismatch and transparent replication. David At 07:00 AM 2/29/00 -0800, Craig Dickson wrote: >James Hague wrote: > >> IMO Erlang is the best functional language for AI work, because of atoms >> and dynamic typing. > >Scheme has both those properties, plus the ability to manipulate code as >data, which I would think terribly useful for AI. Why is Erlang a better >language for AI than Scheme? (I suppose Erlang's concurrency might be >helpful.) > >> I'm still grinding out C++ code at a furious pace during the day, >> unfortunately :) > >Me too (sigh). Any Erlang jobs in Silicon Valley? > >Craig > From jon@REDACTED Fri Mar 3 06:09:21 2000 From: jon@REDACTED (Jon Holdsworth) Date: Fri, 03 Mar 2000 16:09:21 +1100 Subject: Solaris 2.7 - looks like our fault Message-ID: <38BF4901.223294EC@eddieware.org> Hello all It actually looks like it was some patches that I forgot my script was applying caused 49 not to compile under Solaris 2.7 So far it seems to compile fine without them. Investigating... Jon Holdsworth From jon@REDACTED Fri Mar 3 04:01:07 2000 From: jon@REDACTED (Jon Holdsworth) Date: Fri, 03 Mar 2000 14:01:07 +1100 Subject: Help! Compiling Erlang 49 (otp_src_R6B-0) on Solaris 2.7, no joy Message-ID: <38BF2AF3.7B5C18F1@eddieware.org> Hello all, I am new to this list I am compiling Erlang 49 (otp_src_R6B-0), the open source version, on Solaris 2.7 So far I have not managed to get this to work. I have searched the archives of this mailing list, enquired of ericsson people, and searched the web, to no avail. Can anybody help, has anybody got this to compile yet ? Jon Holdsworth Transcript of the ./configure and make output is given below: ./configure checking host system type... sparc-sun-solaris2.7 checking for GNU make... yes (make) checking for a BSD compatible install... /usr/jon/erlang49/otp_src_R6B-0/erts/autoconf/install-sh -c checking whether ln -s works... yes checking for ranlib... : Running configure in erts/autoconf... creating cache /usr/jon/erlang49/otp_src_R6B-0/erts/autoconf/sparc-sun-solaris2.7/config.cache checking host system type... sparc-sun-solaris2.7 checking for gcc... gcc checking whether the C compiler (gcc ) works... yes checking whether the C compiler (gcc ) is a cross-compiler... no checking whether we are using GNU C... yes checking whether gcc accepts -g... yes checking for POSIXized ISC... no checking for gcc... (cached) gcc checking whether the C compiler (gcc -g -O2 ) works... yes checking whether the C compiler (gcc -g -O2 ) is a cross-compiler... no checking whether we are using GNU C... (cached) yes checking whether gcc accepts -g... (cached) yes checking for ranlib... : checking for flex... lex checking for yywrap in -ll... yes checking for bison... no checking for byacc... no checking for gawk... no checking for mawk... no checking for nawk... nawk checking for perl5... no checking for perl... /usr/local/bin/perl checking whether ln -s works... yes checking for ar... ar checking for a BSD compatible install... /usr/ucb/install -c checking how to create a directory including parents... /usr/ucb/install -c -d checking for extra flags needed to export symbols... none checking for sin in -lm... yes checking for dlopen in -ldl... yes checking for main in -linet... no checking for main in -lresolv... yes checking for tgetent in -ltermlib... yes checking for connect... no checking for main in -lsocket... yes checking for gethostbyname... no checking for main in -lnsl... yes checking for gethostbyname_r... yes checking for dirent.h that defines DIR... yes checking for opendir in -ldir... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/wait.h that is POSIX.1 compatible... yes checking whether time.h and sys/time.h may both be included... yes checking for fcntl.h... yes checking for limits.h... yes checking for unistd.h... yes checking for syslog.h... yes checking for dlfcn.h... yes checking for ieeefp.h... yes checking for thread.h... yes checking for pthread.h... yes checking for sys/ioctl.h... yes checking for sys/time.h... yes checking for sys/uio.h... yes checking for sys/sockio.h... yes checking for sys/socketio.h... no checking for net/errno.h... no checking for pthread/mit/pthread.h... no checking for SO_BSDCOMPAT declaration... no checking for INADDR_LOOPBACK in netinet/in.h... yes checking for sys_errlist declaration in stdio.h or errno.h... no checking for working const... yes checking return type of signal handlers... void checking for off_t... yes checking for pid_t... yes checking for size_t... yes checking whether struct tm is in sys/time.h or time.h... time.h checking whether struct sockaddr has sa_len field... no checking for struct exception (and matherr function)... yes checking size of long... 4 checking for ieee_handler... no checking for fpsetmask... yes checking for finite... yes checking for res_gethostbyname... yes checking for dlopen... yes checking for pread... yes checking for pwrite... yes checking for writev... yes checking for memmove... yes checking for strerror... yes checking for gethrtime... yes checking for localtime_r... yes checking for gmtime_r... yes checking whether setvbuf arguments are reversed... no checking for vfork.h... no checking for working vfork... no checking for vprintf... yes checking for conflicting declaration of fread... yes checking for IP version 6 support... no checking for multicast support... yes checking how to correct for time adjustments... hrtime checking whether pointers contains extra bits... no checking for conflicting declaration of fprintf... no checking for /usr/local/ssl/include/openssl/opensslv.h... yes ./configure: syntax error at line 4398: `(' unexpected creating ./config.status creating Makefile configuring in lib running /bin/sh /usr/jon/erlang49/otp_src_R6B-0/lib/configure --cache-file=.././config.cache --srcdir=/usr/jon/erlang49/otp_src_R6B-0/lib creating ./config.status configuring in etk running /bin/sh /usr/jon/erlang49/otp_src_R6B-0/lib/etk/configure --cache-file=../.././config.cache --srcdir=/usr/jon/erlang49/otp_src_R6B-0/lib/etk checking host system type... sparc-sun-solaris2.7 checking for gcc... gcc checking whether the C compiler (gcc ) works... yes checking whether the C compiler (gcc ) is a cross-compiler... no checking whether we are using GNU C... yes checking whether gcc accepts -g... yes checking for ranlib... : checking for tcl7.6 source code... ok checking for tk4.2 source code... ok checking for erlang installation... ok checking how to run the C preprocessor... gcc -E checking for unistd.h... yes checking for limits.h... yes checking for dlfcn.h... yes checking for ANSI C header files... yes checking for mode_t... yes checking for pid_t... yes checking for size_t... yes checking for uid_t in sys/types.h... yes checking whether byte ordering is bigendian... yes checking whether char is unsigned... no checking for getcwd... yes checking for opendir... yes checking for strstr... yes checking for strtol... yes checking for tmpnam... yes checking for waitpid... yes checking for strerror... yes checking for getwd... yes checking for wait3... yes checking for uname... yes checking dirent.h... yes checking for errno.h... yes checking for float.h... yes checking for limits.h... (cached) yes checking for stdlib.h... yes checking for string.h... yes checking for sys/wait.h... yes checking for dlfcn.h... (cached) yes checking for unistd.h... (cached) yes checking fd_set and sys/select... yes checking for sys/time.h... yes checking whether time.h and sys/time.h may both be included... yes checking whether struct tm is in sys/time.h or time.h... time.h checking for tm_zone in struct tm... no checking for tzname... yes checking tm_tzadj in struct tm... no checking tm_gmtoff in struct tm... no checking long timezone variable... yes checking proper strstr implementation... yes checking for strtoul... yes checking for strtod... yes checking for strtod... (cached) yes checking for Solaris strtod bug... ok checking for opendir... (cached) yes checking union wait... no checking matherr support... yes checking for vfork... yes checking vfork/signal bug... ok checking for strncasecmp... yes checking for BSDgettimeofday... no checking for gettimeofday... yes checking for gettimeofday declaration... present checking for main in -linet... no checking for net/errno.h... no checking system version (for dynamic loading)... SunOS-5.7 checking for dlopen in -ldl... yes checking for UnixWare -o bug... OK checking for sys/ioctl.h... yes checking for sys/filio.h... yes checking FIONBIO vs. O_NONBLOCK for nonblocking I/O... O_NONBLOCK checking for X... libraries /usr/openwin/lib, headers /usr/openwin/include checking for main in -lXbsd... no checking for connect... no checking for main in -lsocket... yes checking for gethostbyname... no checking for main in -lnsl... yes checking for sin... no checking for memmove... yes checking whether to build with support for threads... yes checking for thr_create in -lthread... yes checking if INADDR_LOOPBACK is in netinet/in.h... yes creating ./config.status creating c_src/sparc-sun-solaris2.7/Makefile configuring in gs running /bin/sh /usr/jon/erlang49/otp_src_R6B-0/lib/gs/configure --cache-file=../.././config.cache --srcdir=/usr/jon/erlang49/otp_src_R6B-0/lib/gs checking host system type... sparc-sun-solaris2.7 checking where to find the tcl/tk libraries... using sources in c_src/lib checking for gcc... gcc checking whether the C compiler (gcc ) works... yes checking whether the C compiler (gcc ) is a cross-compiler... no checking whether we are using GNU C... yes checking whether gcc accepts -g... yes checking for ranlib... : checking how to run the C preprocessor... gcc -E checking for POSIXized ISC... no checking for X... libraries /usr/openwin/lib, headers /usr/openwin/include checking for IceConnectionNumber in -lICE... yes checking for dnet_ntoa in -ldnet... no checking for t_accept in -lnsl... yes checking for socket in -lsocket... yes checking for main in -lSM... yes /usr/jon/erlang49/otp_src_R6B-0/lib/gs/configure: R6_XLIBS: not found checking for connect... no checking for main in -lsocket... yes checking for gethostbyname... no checking for main in -lnsl... yes checking for gethostbyname_r... yes checking whether gcc needs -traditional... no checking for sin in -lm... yes checking for dlopen in -ldl... yes creating ./config.status creating c_src/sparc-sun-solaris2.7/Makefile configuring in c_src/lib/tcl7.6/unix running /bin/sh /usr/jon/erlang49/otp_src_R6B-0/lib/gs/c_src/lib/tcl7.6/unix/configure --cache-file=../../../../../.././config.cache --srcdir=/usr/jon/erlang49/otp_src_R6B-0/lib/gs/c_src/lib/tcl7.6/unix creating cache ../../../../../.././config.cache checking for ranlib... : checking for gcc... gcc checking whether the C compiler (gcc ) works... yes checking whether the C compiler (gcc ) is a cross-compiler... no checking whether we are using GNU C... yes checking whether gcc accepts -g... yes checking for getcwd... yes checking for opendir... yes checking for strstr... yes checking for strtol... yes checking for tmpnam... yes checking for waitpid... yes checking for strerror... yes checking for getwd... yes checking for wait3... yes checking for uname... yes checking for sin... no checking for main in -lieee... no checking dirent.h... yes checking how to run the C preprocessor... gcc -E checking for errno.h... yes checking for float.h... yes checking for limits.h... yes checking for stdlib.h... yes checking for string.h... yes checking for sys/wait.h... yes checking for dlfcn.h... yes checking for unistd.h... yes checking fd_set and sys/select... yes checking for sys/time.h... yes checking whether time.h and sys/time.h may both be included... yes checking whether struct tm is in sys/time.h or time.h... time.h checking for tm_zone in struct tm... no checking for tzname... yes checking tm_tzadj in struct tm... no checking tm_gmtoff in struct tm... no checking long timezone variable... yes checking proper strstr implementation... yes checking for strtoul... yes checking for strtod... yes checking for strtod... (cached) yes checking for Solaris strtod bug... ok checking for ANSI C header files... yes checking for mode_t... yes checking for pid_t... yes checking for size_t... yes checking for uid_t in sys/types.h... yes checking whether byte ordering is bigendian... yes checking for opendir... (cached) yes checking union wait... no checking matherr support... yes checking for vfork... yes checking vfork/signal bug... ok checking for strncasecmp... yes checking for BSDgettimeofday... no checking for gettimeofday... yes checking for gettimeofday declaration... present checking for main in -linet... no checking for net/errno.h... no checking for connect... no checking for main in -lsocket... yes checking for gethostbyname... no checking for main in -lnsl... yes checking system version (for dynamic loading)... SunOS-5.7 checking for dlopen in -ldl... yes checking for UnixWare -o bug... OK checking for sys/ioctl.h... yes checking for sys/filio.h... yes checking FIONBIO vs. O_NONBLOCK for nonblocking I/O... O_NONBLOCK updating cache ../../../../../.././config.cache creating ./config.status creating Makefile creating tclConfig.sh creating pkgIndex.tcl configuring in c_src/lib/tk4.2/unix running /bin/sh /usr/jon/erlang49/otp_src_R6B-0/lib/gs/c_src/lib/tk4.2/unix/configure --cache-file=../../../../../.././config.cache --srcdir=/usr/jon/erlang49/otp_src_R6B-0/lib/gs/c_src/lib/tk4.2/unix loading cache ../../../../../.././config.cache checking for ranlib... (cached) : checking for gcc... (cached) gcc checking whether the C compiler (gcc ) works... yes checking whether the C compiler (gcc ) is a cross-compiler... no checking whether we are using GNU C... (cached) yes checking whether gcc accepts -g... (cached) yes checking how to run the C preprocessor... (cached) gcc -E checking for unistd.h... (cached) yes checking for limits.h... (cached) yes checking for dlfcn.h... (cached) yes checking stdlib.h... yes checking for ANSI C header files... (cached) yes checking for mode_t... (cached) yes checking for pid_t... (cached) yes checking for size_t... (cached) yes checking for uid_t in sys/types.h... (cached) yes checking for X... libraries /usr/openwin/lib, headers /usr/openwin/include checking for main in -lXbsd... no checking for connect... (cached) no checking for main in -lsocket... (cached) yes checking for gethostbyname... (cached) no checking for main in -lnsl... (cached) yes checking for sin... (cached) no checking for main in -lieee... (cached) no checking for memmove... yes checking whether char is unsigned... no checking for strtod... (cached) yes checking for Solaris 2.4 strtod bug... ok checking standalone support of Tcl... don't know == Warning: Your libtcl7.6.a is not yet created in the directory /usr/jon/erlang49/otp_src_R6B-0/lib/gs/c_src/lib/tcl7.6/unix, so I cannot determine this. For now I just assume there is standalone support. If you get an error later during the build of wish.standalone, then first compile Tcl7.6 with standalone support. checking for UnixWare -o bug... OK updating cache ../../../../../.././config.cache creating ./config.status creating Makefile creating tkConfig.sh creating pkgIndex.tcl make cd erts && ERL_TOP=/usr/jon/erlang49/otp_src_R6B-0 make NO_START_SCRIPTS=true opt make[1]: Entering directory `/usr/jon/erlang49/otp_src_R6B-0/erts' make[2]: Entering directory `/usr/jon/erlang49/otp_src_R6B-0/erts/emulator' make -f sparc-sun-solaris2.7/Makefile TYPE=opt make[3]: Entering directory `/usr/jon/erlang49/otp_src_R6B-0/erts/emulator' make[3]: sparc-sun-solaris2.7/Makefile: No such file or directory make[3]: *** No rule to make target `sparc-sun-solaris2.7/Makefile'. Stop. make[3]: Leaving directory `/usr/jon/erlang49/otp_src_R6B-0/erts/emulator' make[2]: *** [opt] Error 2 make[2]: Leaving directory `/usr/jon/erlang49/otp_src_R6B-0/erts/emulator' make[2]: Entering directory `/usr/jon/erlang49/otp_src_R6B-0/erts/etc' make[3]: Entering directory `/usr/jon/erlang49/otp_src_R6B-0/erts/etc/common' make -f sparc-sun-solaris2.7/Makefile TYPE=opt make[4]: Entering directory `/usr/jon/erlang49/otp_src_R6B-0/erts/etc/common' make[4]: sparc-sun-solaris2.7/Makefile: No such file or directory make[4]: *** No rule to make target `sparc-sun-solaris2.7/Makefile'. Stop. make[4]: Leaving directory `/usr/jon/erlang49/otp_src_R6B-0/erts/etc/common' make[3]: *** [opt] Error 2 make[3]: Leaving directory `/usr/jon/erlang49/otp_src_R6B-0/erts/etc/common' make[2]: *** [opt] Error 2 make[2]: Leaving directory `/usr/jon/erlang49/otp_src_R6B-0/erts/etc' make[2]: Entering directory `/usr/jon/erlang49/otp_src_R6B-0/erts/epmd' Makefile:19: /usr/jon/erlang49/otp_src_R6B-0/make/sparc-sun-solaris2.7/otp.mk: No such file or directory make[2]: *** No rule to make target `/usr/jon/erlang49/otp_src_R6B-0/make/sparc-sun-solaris2.7/otp.mk'. Stop. make[2]: Leaving directory `/usr/jon/erlang49/otp_src_R6B-0/erts/epmd' make[1]: *** [opt] Error 2 make[1]: Leaving directory `/usr/jon/erlang49/otp_src_R6B-0/erts' make: *** [emulator] Error 2 End Of Transcript From ruy@REDACTED Fri Mar 3 16:31:07 2000 From: ruy@REDACTED (Ruy de Queiroz) Date: Fri, 3 Mar 2000 12:31:07 -0300 (EST) Subject: 7th WoLLIC'2000 Message-ID: [Please post. Apologies for multiple copies.] Call for Contributions 7th Workshop on Logic, Language, Information and Computation (WoLLIC'2000) August 15-18, 2000 ! TUTORIALS >> (Tutorial Day: August 15th) << TUTORIALS ! Natal, Brazil The "7th Workshop on Logic, Language, Information and Computation" (WoLLIC'2000), the seventh version of a series of workshops which started in 1994 with the aim of fostering interdisciplinary research in pure and applied logic, will be held in Natal, Brazil, from August 15th to 18th 2000. Contributions are invited in the form of short papers (10 A4 10pt pages) in all areas related to logic, language, information and computation, including: pure logical systems, proof theory, model theory, algebraic logic, type theory, category theory, constructive mathematics, lambda and combinatorial calculi, program logic and program semantics, logics and models of concurrency, logic and complexity theory, nonclassical logics, nonmonotonic logic, logic and language, discourse representation, logic and artificial intelligence, automated deduction, foundations of logic programming, logic and computation, and logic engineering. The 7th WoLLIC'2000 has the scientific sponsorship of the Association for Symbolic Logic (ASL), the Interest Group in Pure and Applied Logics (IGPL), the European Association for Logic, Language and Information (FoLLI), the Sociedade Brasileira de Computacao (SBC), and the Sociedade Brasileira de Logica (SBL). THE LOCATION Natal is the capital and largest city of Rio Grande do Norte, a sun shiny land of beaches, dunes, coconut trees, located in north-east coast of Brazil. There, the summer takes all year long (sun shines more than 300 days per year), and the heat is softened by a constant breeze. Along the 400-kilometer (250-mile) coast line, calm beaches with reefs forming natural pools altern with good surfing spots, almost untouched places full of sand dunes and coconut trees. GUEST SPEAKERS There will be a number of guest speakers, including: Andrea Asperti (Univ Bologna, Italy) Angus Macintyre (Edinburgh Univ, Scotland) Luiz Carlos Pereira (Pontificial Catholic Univ of Rio, Brazil) Toniann Pitassi (Arizona Univ, USA) Bruno Poizat (Univ Lyon I, France) Glynn Winskel (BRICS, Denmark) SUBMISSION: Papers (up to 10 pages A4 10pt, sent preferably in postscript format by e-mail to wollic@REDACTED, or in 5(five) copies to postal address) must be RECEIVED by MAY 7th, 2000 by the Chair of the Organising Committee. Papers must be ANONYMOUS (a separate identification page must be included), written in English and give enough detail to allow the programme committee to assess the merits of the work. Papers should start with a brief statement of the issues, a summary of the main results, and a statement of their significance and relevance to the workshop. References and comparisons with related work is also expected. Technical development directed to the specialist should follow. Results must be unpublished and not submitted for publication elsewhere, including the proceedings of other symposia or workshops. One author of each accepted paper will be expected to attend the conference in order to present it. Authors will be notified of acceptance by JUNE 9th, 2000, and final versions will have to be delivered (in LaTeX format) by JUNE 16th, 2000. The abstracts of the papers will be published in a "Conference Report" section of the Logic Journal of the IGPL (ISSN 1367-0751) (Oxford Univ Press) as part of the meeting report. Papers presented at the meeting will be invited for submission (in full version) to the Logic Journal of the IGPL (http://www.oup.co.uk/igpl/). IMPORTANT DATES: Submission: May 7th, 2000 Notification of acceptance/rejection: June 9th, 2000 Delivery of final (in LaTeX): June 16th, 2000 PROGRAMME COMMITTEE: Sergei Artemov (Moscow Univ, Russia, and Cornell Univ, USA), Ricardo Bianconi (Univ Sao Paulo, Brazil), Sam Buss (UC San Diego, USA), Edmund Clarke (Carnegie-Mellon Univ, USA), Itala D'Ottaviano (Univ Campinas, Brazil), Heinz-Dieter Ebbinghaus (Univ Freiburg, Germany), Peter Johnstone (Cambridge Univ, UK), Hans Kamp (Univ Stuttgart, Germany), Pat Lincoln (SRI International, USA), Maarten de Rijke (Amsterdam Univ, The Netherlands), Colin Stirling (Edinburgh Univ, Scotland). ORGANISING COMMITTEE: B. C. Bedregal (UFRN), M. E. Coniglio (UNICAMP), A. M. P. Cruz (UFRN), D. Deharbe (UFRN), A. T. C. Martins (UFC), A. Moreira (UFRN), A. G. de Oliveira (UFPE/UFBA), R. de Queiroz (UFPE), R. H. N. Santiago (UFRN). For further information, contact the Chair of the Organising Committee: Ruy de Queiroz, Centro de Informatica, Univ. Federal de Pernambuco, CP 7851, 50732-970 Recife, PE, Brazil. E-mail: ruy@REDACTED, tel.: (+55 81) 271-8430, fax: (+55 81) 271-8438. WEB PAGE: http://www.di.ufpe.br/~wollic/wollic2000/ From jamesh@REDACTED Fri Mar 3 20:15:12 2000 From: jamesh@REDACTED (James Hague) Date: Fri, 03 Mar 2000 13:15:12 -0600 Subject: Internal binary representation Message-ID: <3.0.32.20000303131511.00d59d14@volition-inc.com> I've read "Protocol Programming in Erlang Using Binaries," the experimental prototype for Erlang's upcoming enhancements to binaries. In this doc, there's an explanation of how binaries are represented internally. My question: Is this similar to how binaries are currently implemented or simply how the prototype worked? Mostly, I'm curious how expensive split_binary is. I know it returns two new binaries in addition to the original, but is that done on a logical level or does it copy the data? James (please email a response in addition to a public reply) From jhague@REDACTED Sat Mar 4 03:23:37 2000 From: jhague@REDACTED (James Hague) Date: Fri, 3 Mar 00 20:23:37 -0600 Subject: Erlang Versus Python Message-ID: <200003040221.UAA27188@node-03.advancenet.net> >Python has some functional features, though they're not as well >integrated into the language as they could be. Interestingly, I recall reading an interview with Guido in, I believe, Linux Journal. In response to a "What would you do differently?" sort of question, he responded that he thought he listened to the functional language advocates too much, and some of the features they requested--that were added to Python--maybe weren't in the best interests of the language. Or somesuch. This is from memory :) James From davidg@REDACTED Sat Mar 4 07:13:54 2000 From: davidg@REDACTED (David Gould) Date: Fri, 3 Mar 2000 22:13:54 -0800 Subject: Erlang Versus Python In-Reply-To: <200003040221.UAA27188@node-03.advancenet.net>; from James Hague on Thu, Apr 10, 2036 at 02:51:53AM -0600 References: <200003040221.UAA27188@node-03.advancenet.net> Message-ID: <20000303221354.D10507@dnai.com> On Thu, Apr 10, 2036 at 02:51:53AM -0600, James Hague wrote: > >Python has some functional features, though they're not as well > >integrated into the language as they could be. > > Interestingly, I recall reading an interview with Guido in, I believe, > Linux Journal. In response to a "What would you do differently?" sort of > question, he responded that he thought he listened to the functional > language advocates too much, and some of the features they > requested--that were added to Python--maybe weren't in the best interests > of the language. Or somesuch. This is from memory :) Btw, there is a nifty little patch to Python that adds list comprehensions. The amazing thing is just how simple the patch is. -dg -- David Gould davidg@REDACTED 510.536.1443 - If simplicity worked, the world would be overrun with insects. - From bjorn@REDACTED Sat Mar 4 22:02:09 2000 From: bjorn@REDACTED (Bjorn Gustavsson) Date: 04 Mar 2000 22:02:09 +0100 Subject: Internal binary representation In-Reply-To: James Hague's message of Fri, 03 Mar 2000 13:15:12 -0600 References: <3.0.32.20000303131511.00d59d14@volition-inc.com> Message-ID: James Hague writes: > > I've read "Protocol Programming in Erlang Using Binaries," the experimental > prototype for Erlang's upcoming enhancements to binaries. In this doc, > there's an explanation of how binaries are represented internally. My > question: Is this similar to how binaries are currently implemented or > simply how the prototype worked? The current implementation (R6B) has only reference-counted binaries, not the other binaries. We plan to add on-heap binaries and sub-binaries (called tail-binaries in the protoype) in R7. The segmented binaries we find far too complicated. > > Mostly, I'm curious how expensive split_binary is. I know it returns two > new binaries in addition to the original, but is that done on a logical > level or does it copy the data? There is no copying of the binary data itself, but for each split_binary two instances of an internal structure is built and linked into a linked list. There will be a slight cost at garbage-collection time to traverse that list. /Bjorn -- Bj?rn Gustavsson Ericsson Utvecklings AB bjorn@REDACTED ?T2/UAB/F/P BOX 1505 125 25 ?lvsj? From gandalf@REDACTED Mon Mar 6 18:02:01 2000 From: gandalf@REDACTED (Vladimir Ulogov) Date: Mon, 06 Mar 2000 12:02:01 -0500 Subject: Erlang Versus Python References: <200003040221.UAA27188@node-03.advancenet.net> Message-ID: <38C3E489.2D9627CC@control.att.com> James Hague wrote: > requested--that were added to Python--maybe weren't in the best interests > of the language. Or somesuch. This is from memory :) If we will going back to the Python history, it's never was designed and implemented as functional language, unlike Erlang. So, it having functions and some as I can say advanced parameters handling, but: - no pattern matching; - nested functions are not too easy - functions are not a data (it possibly to use the functions as a data, but it's require some triks) In Erlang red book, we can read about some ways of the "object oriented" approaches for Erlang, but IMHO this is not too serious. It's taff for functional language to be a OO at the same time :) > > James -- %% Vladimir I. Ulogov (gandalf@REDACTED) AT&T Labs "Where lands meets water. Where earth meets air. Where body meets mind. Where space meets time. We like to be on one side, and look at the other." D.Adams "Mostly harmless" From bparsia@REDACTED Mon Mar 6 22:18:12 2000 From: bparsia@REDACTED (Bijan Parsia) Date: Mon, 6 Mar 2000 16:18:12 -0500 (EST) Subject: Erlang Versus Python In-Reply-To: <38C3E489.2D9627CC@control.att.com> Message-ID: --On Monday, March 06, 2000, 12:02 PM -0500 Vladimir Ulogov wrote: > James Hague wrote: > >> requested--that were added to Python--maybe weren't in the best interests >> of the language. Or somesuch. This is from memory :) > If we will going back to the Python history, it's never was designed and > implemented as functional language, unlike Erlang. So, it having > functions and some as I can say advanced parameters handling, but: > - no pattern matching; Actually, a very, very limited sort is available in multiple assignment. > - nested functions are not too easy Hmm. I don't see that that's a requirement for functionality. > - functions are not a data (it possibly to use the functions as a data, > but it's require some triks) Actually, it's quite easy to manipulate function (and other code) objects (this is from the Python repl): >>> def square(n): return n*n [Defines a function and binds it to the name 'square'.] >>> square(4) 16 [applies the function stored in 'square' to 4. You can "change" square by reassignment.] >>> square >>> y=square >>> y >>> y==square 1 >>> y(4) 16 >>> apply(y, (4,)) 16 ------------ You get the idea. You can also programmatically create function objects via compile() and friends. So, where're the tricks? ;) > In Erlang red book, we can read about some ways of the "object oriented" > approaches for Erlang, but IMHO this is not too serious. It's taff for > functional language to be a OO at the same time :) O'cml and friends ;) RScheme, Common Lisp, Hugs. Now, whether these are both *good* functional langauges and 00 lauguages *and* found it easy to be so is a different issue. Cheers, Bijan Parsia. From atif_m_m_taha@REDACTED Tue Mar 7 11:22:22 2000 From: atif_m_m_taha@REDACTED (atif taha) Date: 7 Mar 00 03:22:22 MST Subject: No subject Message-ID: <20000307102222.1160.qmail@nwcst322.netaddress.usa.net> Dear Sir, I am a graduate student working in my M. Sc. Program in Computer Sciences. I am now working on a project about using Erlang as a communication programming language; and the possibility to include this as a part of the Computer Sciences B. Sc. Program in my faculty. While running a program written in Microsoft WordPad on Windows95 platform I faced a problem. The program name is: math1.era The path is: C:\Program Files \era 4.9.1\math1 Erlang programs are in the directory: C:\Program Files \era 4.9.1 The program syntax is: - module (math1). - export ([factorail/1]). factorial (0) -> 1; factorial (n) -> n* factorial (n-1); The error massage is: ./ math1.era: next form/ expression contains unterminated string stating with ? \000\ 062 Default prgr? ./ math1.era: 7: no module definition error I would be utmost grateful if you kindly lent me some help to understand what the problem is, what reasons might cause it, and what are the possible solutions. May I humbly ask for your permission to write for your end seeking help and advice have I faced any further problems in the future. I will be looking forward to receive a reply from you soonly. Best regards Sincerely yours Manahil A. Elgalil Dramaly@REDACTED ____________________________________________________________________ Get free email and a permanent address at http://www.netaddress.com/?N=1 From sam@REDACTED Tue Mar 7 11:35:47 2000 From: sam@REDACTED (Samuel Tardieu) Date: Tue, 7 Mar 2000 11:35:47 +0100 Subject: Erlang Versus Python In-Reply-To: ; from bparsia@email.unc.edu on Mon, Mar 06, 2000 at 04:18:12PM -0500 References: <38C3E489.2D9627CC@control.att.com> Message-ID: <2000-03-07-11-35-47+trackit+sam@inf.enst.fr> | You get the idea. You can also programmatically create function objects | via compile() and friends. So, where're the tricks? ;) I notice that you don't mention closures :) Eshell V4.9.1 (abort with ^G) 1> F = fun (X) -> fun (Y) -> X * Y end end. #Fun 2> G = F (5). #Fun 3> G (3). 15 4> G (4). 20 In Python, you don't capture any external variable. Python 1.5.2 (#2, Feb 18 2000, 05:02:29) [GCC 2.95.2 19991024 (release)] on freebsd4 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam >>> def F (X): ... def G (Y): return X*Y ... return G ... >>> G = F (5) >>> G (3) Traceback (innermost last): File "", line 1, in ? File "", line 2, in G NameError: X You have to "cheat" by using default arguments: >>> def F (X): ... def G (Y, X=X): return X * Y ... return G ... >>> G = F (5) >>> G (3) 15 >>> G (4) 20 The "X=X" construct reads "when not supplied, the X parameter will be equal to (resolved at compile time) X". In fact, G is a 2-args function with a default second parameter, not a 1-arg one as Erlang or ML return. From luke@REDACTED Tue Mar 7 11:39:21 2000 From: luke@REDACTED (Luke Gorrie) Date: 07 Mar 2000 11:39:21 +0100 Subject: none In-Reply-To: atif taha's message of "7 Mar 00 03:22:22 MST" References: <20000307102222.1160.qmail@nwcst322.netaddress.usa.net> Message-ID: atif taha writes: > I would be utmost grateful if you kindly lent me some help to understand wha > the problem is, what reasons might cause it, and what are the possible > solutions. There are a few syntactic problems with the program. I think you might like to download Concurrent Programming in Erlang (part 1) from www.erlang.org and give it a quick read. Conveniently enough, a working factorial program is explained on the first page of chapter 1. Cheers, Luke From atif_m_m_taha@REDACTED Tue Mar 7 12:35:24 2000 From: atif_m_m_taha@REDACTED (atif dahab) Date: Tue, 07 Mar 2000 03:35:24 PST Subject: ask about the course Message-ID: <20000307113524.72762.qmail@hotmail.com> Dear Sir, I am a graduate student working in my M. Sc. Program in Computer Sciences. I am now working on a project about using Erlang as a communication programming language; and the possibility to include this as a part of the Computer Sciences B. Sc. Program in my faculty. While running a program written in Microsoft WordPad on Windows95 platform I faced a problem. The program name is: math1.era The path is: C:\Program Files \era 4.9.1\math1 Erlang programs are in the directory: C:\Program Files \era 4.9.1 The program syntax is: - module (math1). - export ([factorail/1]). factorial (0) -> 1; factorial (n) -> n* factorial (n-1); The error massage is: ./ math1.era: next form/ expression contains unterminated string stating with ? \000\ 062 Default prgr? ./ math1.era: 7: no module definition error I would be utmost grateful if you kindly lent me some help to understand what the problem is, what reasons might cause it, and what are the possible solutions. May I humbly ask for your permission to write for your end seeking help and advice have I faced any further problems in the future. I will be looking forward to receive a reply from you soonly. Best regards Sincerely yours Manahil A. Elgalil Dramaly@REDACTED ______________________________________________________ Get Your Private, Free Email at http://www.hotmail.com From atif_m_m_taha@REDACTED Tue Mar 7 12:36:27 2000 From: atif_m_m_taha@REDACTED (atif dahab) Date: Tue, 07 Mar 2000 03:36:27 PST Subject: quation how to use erlang Message-ID: <20000307113627.5234.qmail@hotmail.com> Dear Sir, I am a graduate student working in my M. Sc. Program in Computer Sciences. I am now working on a project about using Erlang as a communication programming language; and the possibility to include this as a part of the Computer Sciences B. Sc. Program in my faculty. While running a program written in Microsoft WordPad on Windows95 platform I faced a problem. The program name is: math1.era The path is: C:\Program Files \era 4.9.1\math1 Erlang programs are in the directory: C:\Program Files \era 4.9.1 The program syntax is: - module (math1). - export ([factorail/1]). factorial (0) -> 1; factorial (n) -> n* factorial (n-1); The error massage is: ./ math1.era: next form/ expression contains unterminated string stating with ? \000\ 062 Default prgr? ./ math1.era: 7: no module definition error I would be utmost grateful if you kindly lent me some help to understand what the problem is, what reasons might cause it, and what are the possible solutions. May I humbly ask for your permission to write for your end seeking help and advice have I faced any further problems in the future. I will be looking forward to receive a reply from you soonly. Best regards Sincerely yours Manahil A. Elgalil Dramaly@REDACTED ______________________________________________________ Get Your Private, Free Email at http://www.hotmail.com From rv@REDACTED Tue Mar 7 13:04:29 2000 From: rv@REDACTED (Robert Virding) Date: Tue, 07 Mar 2000 13:04:29 +0100 Subject: quation how to use erlang In-Reply-To: Your message of "Tue, 07 Mar 2000 03:36:27 PST." <20000307113627.5234.qmail@hotmail.com> Message-ID: <200003071204.NAA04644@trana.bluetail.com> "atif dahab" writes: > >While running a program written in Microsoft WordPad on Windows95 platform >I faced a problem. > >The program name is: math1.era >The path is: C:\Program Files \era 4.9.1\math1 >Erlang programs are in the directory: C:\Program Files \era 4.9.1 > >The program syntax is: >- module (math1). >- export ([factorail/1]). >factorial (0) -> 1; >factorial (n) -> n* factorial (n-1); > >The error massage is: > >./ math1.era: next form/ expression contains unterminated string stating >with ? >\000\ 062 Default prgr? >./ math1.era: 7: no module definition >error My first guess would be that WordPad is adding formatting information to the fle not just the program text. Erlang treats everything as program text. My sggestion would be to turn off this on output in Wordpad if possible or use anoher editor like NotePad which only outputs the text or Emacs for which there i a good Erlang mode. Another point is that in Erlang variables start with a capital letter, the `n'in your example is the atom 'n' which would give a runtime error. The last cluse in a function ends in a `.' not a `;' so: -module (math1). -export ([factorial/1]). factorial (0) -> 1; factorial (N) -> N * factorial (N-1). Robert -- Robert Virding Tel: +46 (0)8 692 22 12 Bluetail AB Email: rv@REDACTED Hantverkargatan 78 WWW: http://www.bluetail.com SE-112 38 Stockholm, SWEDEN "Folk s?ger att jag inte bryr mig om n?gonting, men det skiter jag i". From crd@REDACTED Tue Mar 7 15:44:40 2000 From: crd@REDACTED (Craig Dickson) Date: Tue, 7 Mar 2000 06:44:40 -0800 Subject: No subject References: <20000307102222.1160.qmail@nwcst322.netaddress.usa.net> Message-ID: <001301bf8843$b27bafe0$6f01140a@inkpad> atif taha wrote: >While running a program written in Microsoft WordPad on Windows95 >platform I faced a problem. I bet that's your problem right there. You're editing source code with a word processor that defaults to saving documents in a rich-text format. You need to tell WordPad to save the document as text only, or switch to a text editor rather than a word processor. Craig From Sean.Hinde@REDACTED Thu Mar 9 12:23:35 2000 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Thu, 9 Mar 2000 11:23:35 -0000 Subject: Distributed applications Message-ID: Hi all, I have a very simple application containing a single locally registered gen_server which I want to make distributed in the splendidly described manner of Sam Tardieu for his power outages example. I've set up the 'distributed' kernel parameter with my app name and node names as per the example and set the start_phases to [] in my .app file: {distributed, [{backup, [{test1@REDACTED, {test2@REDACTED, test3@REDACTED}]}]} All files are generated using the standard skeletons in the emacs-mode with 4.9.1. If I start with nodes 2 and 3, application:start(backup) hangs on both. The app then starts fine on test1, but application:start(backup) remains hung on nodes 2 and 3. Restarting various nodes means I can get the application fully running on all nodes at once, which I am not at all sure is the idea of this - is it? Do I need to do stuff with start phases or having different behaviour in the application file for normal and takeover etc for this simple locally registered example? Something else? Any and all help much appreciated. Regards, Sean From gunilla@REDACTED Thu Mar 9 13:22:25 2000 From: gunilla@REDACTED (Gunilla Hugosson) Date: Thu, 09 Mar 2000 13:22:25 +0100 Subject: Distributed applications References: Message-ID: <38C79781.19574C4C@erix.ericsson.se> Hi Sean, You need to make sure that the nodes are synchronized using the kernel parameters sync_nodes_mandatory, sync_nodes_optional and sync_nodes_timeout. And, more important, distributed applications doesn't work if you start the applications manually from the shell using application:start(App), you have to generate a boot script which starts the application automatically. (I'm investigating why this is the case, as part of the ongoing work we are doing on release handling). / Gunilla Sean Hinde wrote: > > Hi all, > > I have a very simple application containing a single locally registered > gen_server which I want to make distributed in the splendidly described > manner of Sam Tardieu for his power outages example. > > I've set up the 'distributed' kernel parameter with my app name and node > names as per the example and set the start_phases to [] in my .app file: > > {distributed, [{backup, [{test1@REDACTED, {test2@REDACTED, test3@REDACTED}]}]} > > All files are generated using the standard skeletons in the emacs-mode with > 4.9.1. > > If I start with nodes 2 and 3, application:start(backup) hangs on both. > The app then starts fine on test1, but application:start(backup) remains > hung on nodes 2 and 3. > > Restarting various nodes means I can get the application fully running on > all nodes at once, which I am not at all sure is the idea of this - is it? > > Do I need to do stuff with start phases or having different behaviour in the > application file for normal and takeover etc for this simple locally > registered example? Something else? > > Any and all help much appreciated. > > Regards, > Sean From etxuwig@REDACTED Thu Mar 9 13:25:11 2000 From: etxuwig@REDACTED (Ulf Wiger) Date: Thu, 9 Mar 2000 13:25:11 +0100 (MET) Subject: Distributed applications Message-ID: <200003091225.NAA26709@etxb.ericsson.se> > From: Sean Hinde > > Hi all, > > I have a very simple application containing a single locally registered > gen_server which I want to make distributed in the splendidly described > manner of Sam Tardieu for his power outages example. > > I've set up the 'distributed' kernel parameter with my app name and node > names as per the example and set the start_phases to [] in my .app file: > > {distributed, [{backup, [{test1@REDACTED, {test2@REDACTED, test3@REDACTED}]}]} The above is not syntactically correct. I assume it should be: {distributed, [{backup, [test1@REDACTED, {test2@REDACTED, test3@REDACTED}]}]} That is, run backup primarily on test1, but if it fails, run it on either test2 or test3. > All files are generated using the standard skeletons in the emacs-mode with > 4.9.1. > > If I start with nodes 2 and 3, application:start(backup) hangs on both. > The app then starts fine on test1, but application:start(backup) remains > hung on nodes 2 and 3. Are the nodes in contact with each other? You need to make sure that you have the following kernel env variables defined: {sync_nodes_optional, [test1@REDACTED, test2@REDACTED, test3@REDACTED]} {sync_nodes_timeout, Timeout} % you choose the timeout This can be done via the command-line shell, or in a sys.config. > Restarting various nodes means I can get the application fully running on > all nodes at once, which I am not at all sure is the idea of this - is it? No. This is suggests that your nodes are not talking to each other. > Do I need to do stuff with start phases or having different behaviour in the > application file for normal and takeover etc for this simple locally > registered example? No, you shouldn't have to muck around with that. The start phases are good for more complex apps, and their main contribution is to bring order into complex start/restart scenarios. /Uffe Ulf Wiger, Chief Designer AXD 301 Ericsson Telecom AB tfn: +46 8 719 81 95 Varuv?gen 9, ?lvsj? mob: +46 70 519 81 95 S-126 25 Stockholm, Sweden fax: +46 8 719 43 44 From Sean.Hinde@REDACTED Thu Mar 9 13:51:01 2000 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Thu, 9 Mar 2000 12:51:01 -0000 Subject: Distributed applications Message-ID: Hi Gunilla, >You need to make sure that the nodes are synchronized using >the kernel parameters sync_nodes_mandatory, sync_nodes_optional >and sync_nodes_timeout. I got the impression from the docs that this is optional, but if not set then during startup applications would move around needlessly. This would be acceptable if it removed additional dependencies on recovery. >And, more important, distributed applications doesn't work >if you start the applications manually from the shell using >application:start(App), you have to generate a boot script >which starts the application automatically. (I'm investigating >why this is the case, as part of the ongoing work we are doing >on release handling). Ahhh, this is what I am trying to do. I'll try it in my embedded test environment. I must admit that I have been struggling a bit with how release handling may be used to load small patches into a running system without creating complete new release files. I for one would like to see some simplified routines for updating small parts of applications while maintaining the overall properties of the system. Is this part of your new work? What else will be new? Thanks and Regards, Sean From gunilla@REDACTED Thu Mar 9 14:17:41 2000 From: gunilla@REDACTED (Gunilla Hugosson) Date: Thu, 09 Mar 2000 14:17:41 +0100 Subject: Distributed applications References: Message-ID: <38C7A475.38270E62@erix.ericsson.se> Sean Hinde wrote: > > > I must admit that I have been struggling a bit with how release handling may > be used to load small patches into a running system without creating > complete new release files. I for one would like to see some simplified > routines for updating small parts of applications while maintaining the > overall properties of the system. Is this part of your new work? What else > will be new? > The goal for R7 is to make sure that everything that should work, does work. And to make sure the documentation is correct! Release handling is a huge and complicated area which certainly has room for improvements... If we add anything new at all, it will be simple tools/scripts as support for the existing release handling mechanism. I don't think we will have time to look into routines for updating smaller parts until R8. Regards, Gunilla From Sean.Hinde@REDACTED Thu Mar 9 14:30:59 2000 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Thu, 9 Mar 2000 13:30:59 -0000 Subject: Distributed applications Message-ID: > >And, more important, distributed applications doesn't work > >if you start the applications manually from the shell using > >application:start(App), you have to generate a boot script > >which starts the application automatically. (I'm investigating > >why this is the case, as part of the ongoing work we are doing > >on release handling). > > Ahhh, this is what I am trying to do. I'll try it in my embedded test > environment. > Tried it and it works. I've managed to fool it though by pausing the master node using CTRL c for a minute or so. The node gets a big red cross in appmon and the app starts up elsewhere. If I re-introduce the first node by just selecting (c)ontinue from the CTRL c menu, and re-establish contact with net_adm:ping/1, the application continues to exist on both nodes. I guess this is testing partitioned network behaviour. Any suggestions of how to get around this? Rgds, Sean From etxuwig@REDACTED Thu Mar 9 15:40:52 2000 From: etxuwig@REDACTED (Ulf Wiger) Date: Thu, 9 Mar 2000 15:40:52 +0100 (MET) Subject: Distributed applications Message-ID: <200003091440.PAA02811@etxb.ericsson.se> > From: Sean Hinde > > > >And, more important, distributed applications doesn't work > > >if you start the applications manually from the shell using > > >application:start(App), you have to generate a boot script > > >which starts the application automatically. (I'm investigating > > >why this is the case, as part of the ongoing work we are doing > > >on release handling). > > > > Ahhh, this is what I am trying to do. I'll try it in my embedded test > > environment. > > > > Tried it and it works. I've managed to fool it though by pausing the master > node using CTRL c for a minute or so. The node gets a big red cross in > appmon and the app starts up elsewhere. If I re-introduce the first node by > just selecting (c)ontinue from the CTRL c menu, and re-establish contact > with net_adm:ping/1, the application continues to exist on both nodes. I > guess this is testing partitioned network behaviour. Any suggestions of how > to get around this? What you've accomplished is, as you've noted, a partitioned network. The distributed application controller (dist_ac) doesn't attempt to resynchronize in this case (when both nodes think that the other node restarted.) What you can do, if you want to handle the situation yourself, is to write your own program to detect that the network has been partitioned, and take appropriate action (this involves selecting one node for termination, and making it reboot.) One technique that I've found useful is illustrated by the attached program: - A simple gen_server using a hail protocol to find out which nodes are available - Upon {nodeup, N}, send a cast to node N; if the cast reaches the corresp. monitor process on N, it's most likely a partitioned network (this assumes that it takes considerably longer for a node to start, than it does for message passing between nodes.) - For the program to be really safe, it should be started under a supervisor with {maxR, 0}, so that the node restarts if the monitor process crashes. /Uffe Ulf Wiger, Chief Designer AXD 301 Ericsson Telecom AB tfn: +46 8 719 81 95 Varuv?gen 9, ?lvsj? mob: +46 70 519 81 95 S-126 25 Stockholm, Sweden fax: +46 8 719 43 44 -------------- next part -------------- %%%---------------------------------------------------------------------- %%% File : nodemon.erl %%% Author : Ulf Wiger %%% Purpose : Detect partitioned networks %%% Created : 9 Mar 2000 by Ulf Wiger %%%---------------------------------------------------------------------- -module(nodemon). -author('etxuwig@REDACTED'). %% External exports -export([start_link/0, get_nodes/0]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -record(state, {nodes = []}). %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], [{debug,[trace]}]). get_nodes() -> gen_server:multi_call(?MODULE, get_nodes). %%%---------------------------------------------------------------------- %%% Callback functions from gen_server %%%---------------------------------------------------------------------- %%---------------------------------------------------------------------- %% Func: init/1 %% Returns: {ok, State} | %% {ok, State, Timeout} | %% {stop, Reason} %%---------------------------------------------------------------------- init([]) -> net_kernel:monitor_nodes(true), [{?MODULE, N} ! {?MODULE, hail, node()} || N <- nodes()], {ok, #state{}}. %%---------------------------------------------------------------------- %% Func: handle_call/3 %% Returns: {reply, Reply, State} | %% {reply, Reply, State, Timeout} | %% {noreply, State} | %% {noreply, State, Timeout} | %% {stop, Reason, Reply, State} | (terminate/2 is called) %% {stop, Reason, Reply, State} (terminate/2 is called) %%---------------------------------------------------------------------- handle_call(get_nodes, From, S = #state{nodes = Ns}) -> {reply, Ns, S}. %%---------------------------------------------------------------------- %% Func: handle_cast/2 %% Returns: {noreply, State} | %% {noreply, State, Timeout} | %% {stop, Reason, State} (terminate/2 is called) %%---------------------------------------------------------------------- handle_cast({maybe_partitioned_net, Node}, S = #state{nodes = Ns}) -> case lists:member(Node, Ns) of false -> io:format("*****~n" "***** Partitioned network (~p,~p)~n" "*****~n", [node(),Node]); true -> ok end, %% I don't bother to update state here. What we do from now on depends %% on the application. {noreply, S}. %%---------------------------------------------------------------------- %% Func: handle_info/2 %% Returns: {noreply, State} | %% {noreply, State, Timeout} | %% {stop, Reason, State} (terminate/2 is called) %%---------------------------------------------------------------------- handle_info({?MODULE, hail, FromNode}, S = #state{nodes = Ns}) -> {?MODULE, FromNode} ! {?MODULE, hail_ack, node()}, {noreply, S#state{nodes = [FromNode|Ns -- [FromNode]]}}; handle_info({?MODULE, hail_ack, FromNode}, S = #state{nodes = Ns}) -> {noreply, S#state{nodes = [FromNode|Ns -- [FromNode]]}}; handle_info({nodedown, N}, S = #state{nodes = Ns}) -> {noreply, S#state{nodes = Ns -- [N]}}; handle_info({nodeup, N}, S = #state{nodes = Ns}) -> gen_server:cast({?MODULE, N}, {maybe_partitioned_net, node()}), {noreply, S}; handle_info(Msg, State) -> {noreply, State}. %%---------------------------------------------------------------------- %% Func: terminate/2 %% Purpose: Shutdown the server %% Returns: any (ignored by gen_server) %%---------------------------------------------------------------------- terminate(Reason, State) -> ok. %%---------------------------------------------------------------------- %% Func: code_change/3 %% Purpose: Upgrade internal state %% Returns: {ok, NewState} %%---------------------------------------------------------------------- code_change(OldVsn, State, Extra) -> {ok, State}. %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- From etxuwig@REDACTED Thu Mar 9 16:19:05 2000 From: etxuwig@REDACTED (Ulf Wiger) Date: Thu, 9 Mar 2000 16:19:05 +0100 (MET) Subject: (patch install) RE: Distributed applications Message-ID: <200003091519.QAA06988@etxb.ericsson.se> > From: Sean Hinde > I must admit that I have been struggling a bit with how release handling may > be used to load small patches into a running system without creating > complete new release files. I for one would like to see some simplified > routines for updating small parts of applications while maintaining the > overall properties of the system. Is this part of your new work? What else > will be new? You can get pretty far by just using: load_patch(Module, SuspendProcs) -> [sys:suspend(P) || P <- SuspendProcs], code:load_file(Module), [sys:resume(P) || P <- SuspendProcs]. A slightly more involved program is attached (patch.erl). Example: etxuwig@REDACTED > mv tmp/sasl.beam tmp/sasl.beam.bak etxuwig@REDACTED > erl -pa tmp/ Erlang (BEAM) emulator version 4.9.1.1 Eshell V4.9.1.1 (abort with ^G) 1> .... =PROGRESS REPORT==== 9-Mar-2000::16:13:06 === application: sasl started_at: nonode@REDACTED 1> code:which(sasl). "/home/etxuwig/work/otp/otp-r6b_1/lib/sasl-1.8.3/ebin/sasl.beam" 2> PatchF = "tmp/sasl.beam". "tmp/sasl.beam" 3> file:rename(PatchF++".bak", PatchF). ok 4> patch:file(PatchF). patch:18 - supervised procs: [<0.32.0>,<0.31.0>] patch:41 - suspend(<0.32.0>) patch:41 - suspend(<0.31.0>) patch:45 - resume(<0.32.0>) patch:45 - resume(<0.31.0>) ok 5> Ulf Wiger, Chief Designer AXD 301 Ericsson Telecom AB tfn: +46 8 719 81 95 Varuv?gen 9, ?lvsj? mob: +46 70 519 81 95 S-126 25 Stockholm, Sweden fax: +46 8 719 43 44 -------------- next part -------------- %%% %%% The contents of this file are subject to the Erlang Public License, %%% Version 1.0, (the "License"); you may not use this file except in %%% compliance with the License. You may obtain a copy of the License at %%% http://www.erlang.org/license/EPL1_0.txt %%% %%% 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 Original Code is patch_utils-0.1. %%% %%% The Initial Developer of the Original Code is Ericsson Telecom %%% AB. Portions created by Ericsson are Copyright (C), 1998, Ericsson %%% Telecom AB. All Rights Reserved. %%% %%% Contributor(s): ______________________________________. %%% File: patch.erl %%% Author: Ulf Wiger %%% %%% A small program to illustrate how to apply a patch softly. %%% The file/1 function does not call any code_change function, but %%% This would be trivial to add. -module(patch). -vsn('0.1'). -date('2000-03-09'). -author('ulf.wiger@REDACTED'). -export([file/1]). -define(DBG(Fmt, Args), ok=io:format("~p:~p - " ++ Fmt, [?MODULE,?LINE|Args])). file(FileName) -> BaseName = filename:basename(FileName), Module = list_to_atom(filename:basename(BaseName, ".beam")), Processes = get_supervised_procs(Module), ?DBG("supervised procs: ~w~n",[Processes]), [suspend(P) || P <- Processes], code:purge(Module), case code:load_file(Module) of {module, Module} -> [resume(P) || P <- Processes], Which = code:which(Module), if Which /= FileName -> error([{module, Module}, {"code:which returns", Which}]), {error, loaded_module_not_from_patch_dir}; true -> ok end; {error, LoadReason} -> error([{mfa, {code, load_file, [Module]}}, {error, LoadReason}]), [resume(P) || P <- Processes], {error, module_not_loaded} end. suspend(P) -> ?DBG("suspend(~w)~n", [P]), sys:suspend(P). resume(P) -> ?DBG("resume(~w)~n", [P]), sys:resume(P). error(Info) -> error_logger:error_report(Info). %%% ---------------------------------------------------------- %%% # get_supervised_procs %%% Input: Module:atom() %%% Output: %%% Exceptions: %%% Description: Lists all supervised processes that uses this %%% module as callback module %%% ---------------------------------------------------------- %%% io:format is used here to create a prettier and easier to read printout. %%% All io:format statements should be commented when not debugging this func. get_supervised_procs(Module) -> %io:fwrite("~nLook for Module --> ~p~n", [Module]), lists:foldl( fun(Application, Procs) -> %io:fwrite("Application= ~p~n", [Application]), case application_controller:get_master(Application) of Pid when pid(Pid) -> {Root, Mod} = application_master:get_child(Pid), %io:fwrite("Supervisor= ~p (~p)~n", [Mod, Root]), get_procs(supervisor:which_children(Root), Root, Module, Indent = " ") ++ case Module of Mod -> [Root | Procs]; Module -> Procs end; _NoPid -> %io:fwrite(" No PID~n", []), Procs end end, [], [Appl || {Appl, _Name, _Vsn} <- application:which_applications()]). get_procs([{Name, Pid, worker, dynamic} | T], Sup, Module, Indent) when pid(Pid) -> %io:fwrite("~s~p (~p); worker; Modules= dynamic~n", [Indent, Name, Pid]), {ok, Mods} = gen:call(Pid, self(), get_modules), %io:fwrite("~s ~p~n", [Indent, Mods]), case lists:member(Module, Mods) of true -> [Pid | get_procs(T, Sup, Module, Indent)]; false -> get_procs(T, Sup, Module, Indent) end; get_procs([{Name, Pid, worker, Mods} | T], Sup, Module, Indent) when pid(Pid), list(Mods) -> %io:fwrite("~s~p (~p); worker; Modules= ~p~n", [Indent, Name, Pid, Mods]), case lists:member(Module, Mods) of true -> [Pid | get_procs(T, Sup, Module, Indent)]; false -> get_procs(T, Sup, Module, Indent) end; get_procs([{Name, Pid, supervisor, Mods} | T], Sup, Module, Indent) when pid(Pid) -> %io:fwrite("~s~p (~p); supervisor; Modules= ~p~n",[Indent, Name, Pid, Mods]), case lists:member(Module, Mods) of true -> [Pid | get_procs(T, Sup, Module, Indent)]; false -> get_procs(T, Sup, Module, Indent) end ++ get_procs(supervisor:which_children(Pid), Pid, Module, Indent ++ " "); get_procs([H|T], Sup, Module, Indent) -> %io:fwrite("~sUnknown= ~p~n", [Indent, H]), get_procs(T, Sup, Module, Indent); get_procs([], _Sup, _Module, Indent) -> []. From Sean.Hinde@REDACTED Thu Mar 9 18:02:32 2000 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Thu, 9 Mar 2000 17:02:32 -0000 Subject: Distributed applications (global) Message-ID: The next step - the world!!! I now have a globally registered backup app, to which I have added: global:re_register_name(backup, self()), in the init/1 which works, and fails over etc. Fantastic. Next I added the same to another of my apps and changed sys.config : {distributed, [{backup, [test1@REDACTED, {test2@REDACTED, test3@REDACTED}]}, {wap, [test1@REDACTED, {test2@REDACTED, test3@REDACTED}]}]} both apps startup fine initially but if I stop test1, only backup starts up on the new node. dist_ac seems to be stuck with a load of messages in its queue including some {'EXIT' <0.97.0>, normal}s and {internal_restart_appl, wap} stuff. The function is dist_ac:wait_dist_start/7 Restarting the main node has no effect except stuffing up dist_ac even more. I'm not having a good day with this.. Cheers, Sean From etxuwig@REDACTED Thu Mar 9 18:33:44 2000 From: etxuwig@REDACTED (Ulf Wiger) Date: Thu, 9 Mar 2000 18:33:44 +0100 (MET) Subject: Distributed applications (global) In-Reply-To: Message-ID: On Thu, 9 Mar 2000, Sean Hinde wrote: Sean>The next step - the world!!! Sean> Sean>I now have a globally registered backup app, to which I have Sean>added: Sean> Sean> global:re_register_name(backup, self()), Sean> Sean>in the init/1 which works, and fails over etc. Fantastic. Sean> Sean>Next I added the same to another of my apps and changed Sean>sys.config : Sean> Sean>{distributed, [{backup, [test1@REDACTED, {test2@REDACTED, test3@REDACTED}]}, Sean> {wap, [test1@REDACTED, {test2@REDACTED, test3@REDACTED}]}]} Sean> Sean>both apps startup fine initially but if I stop test1, only backup Sean>starts up on the new node. Sean> Sean>dist_ac seems to be stuck with a load of messages in its queue Sean>including some {'EXIT' <0.97.0>, normal}s and Sean>{internal_restart_appl, wap} stuff. The function is Sean>dist_ac:wait_dist_start/7 Could you call process_info(whereis(dist_ac)) and post the result? You could also try erlang:process_display(whereis(dist_ac), backtrace). /Uffe -- Ulf Wiger, Chief Designer AXD 301 Ericsson Telecom AB tfn: +46 8 719 81 95 Varuv?gen 9, ?lvsj? mob: +46 70 519 81 95 S-126 25 Stockholm, Sweden fax: +46 8 719 43 44 From Sean.Hinde@REDACTED Fri Mar 10 11:25:29 2000 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Fri, 10 Mar 2000 10:25:29 -0000 Subject: Distributed applications (global) Message-ID: Thanks Uffe, Here is the trace for the two remaining nodes, I'll also bring in the commercial support guys and let you all know the outcome. > Could you call process_info(whereis(dist_ac)) and post the > result? You could also try > erlang:process_display(whereis(dist_ac), backtrace). Cheers, Sean -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: traces.txt URL: From etxuwig@REDACTED Fri Mar 10 12:12:45 2000 From: etxuwig@REDACTED (Ulf Wiger) Date: Fri, 10 Mar 2000 12:12:45 +0100 (MET) Subject: Distributed applications (global) In-Reply-To: Message-ID: Sean, >From what I can tell, this is what's happening: - dist_ac on test3 is waiting for test2 to start 'db_backup' - dist_ac on test2 is waiting for information from dist_ac about the weight of 'wap' I will dig further, after lunch, but the crux seems to be that the functions dist_ac:wait_dist_start/7 and dist_ac:collect_answers/4 are partly blocking. It's pretty clear that the dist_ac is deadlocked, though. /Uffe On Fri, 10 Mar 2000, Sean Hinde wrote: Sean>Thanks Uffe, Sean> Sean>Here is the trace for the two remaining nodes, I'll also bring in the Sean>commercial support guys and let you all know the outcome. Sean> Sean>> Could you call process_info(whereis(dist_ac)) and post the Sean>> result? You could also try Sean>> erlang:process_display(whereis(dist_ac), backtrace). Sean> Sean>Cheers, Sean>Sean Sean> Sean> -- Ulf Wiger, Chief Designer AXD 301 Ericsson Telecom AB tfn: +46 8 719 81 95 Varuv?gen 9, ?lvsj? mob: +46 70 519 81 95 S-126 25 Stockholm, Sweden fax: +46 8 719 43 44 From etxuwig@REDACTED Fri Mar 10 14:00:44 2000 From: etxuwig@REDACTED (Ulf Wiger) Date: Fri, 10 Mar 2000 14:00:44 +0100 (MET) Subject: Distributed applications (global) In-Reply-To: Message-ID: Sean, I've made a hack to the dist_ac.erl module. I haven't tried it, mind you, but it does compile. I thought you'd like to try it. What I've done is to try to make sure that dist_ac will always respond to the {dist_ac_weight, _, _, _} messages. /Uffe > diff dist_ac.erl .../otp-r6b_1/lib/kernel-2.4.3.1/src/dist_ac.erl 545a546,575 > case keysearch(Name, #appl.name, S#state.appls) of > {value, Appl} -> > Id = Appl#appl.id, > case Id of > run_waiting -> > {?DIST_AC, Node} ! {dist_ac_weight, Name, 0, node()}, > {noreply, S}; > undefined -> > {noreply, > S#state{tmp_locals = [{Name, Weight, Node} | > S#state.tmp_locals]}}; > {takeover, _} -> > {noreply, > S#state{tmp_locals = [{Name, Weight, Node} | > S#state.tmp_locals]}}; > {failover, _} -> > {noreply, > S#state{tmp_locals = [{Name, Weight, Node} | > S#state.tmp_locals]}}; > _ -> > MyWeight = get_cached_weight(Name, S), > {?DIST_AC, Node} ! {dist_ac_weight, Name, MyWeight, node()}, > NTWs = keyreplaceadd(Name, 1, S#state.tmp_weights, > {Name, MyWeight}), > {noreply, S#state{tmp_weights = NTWs}} > end; > _ -> > {noreply, > S#state{tmp_locals = [{Name, Weight, Node} | S#state.tmp_locals]}} > end; 547,550d576 < %% UW patch: broke out the code into its own function < NewS = answer_weight(Name, Weight, Node, S), < {noreply, NewS}; < 786,788d811 < do_wait_dist_start(Node, Appl, Name, Nodes, PermittedNodes, S, Type). < < do_wait_dist_start(Node, Appl, Name, Nodes, PermittedNodes, S, Type) -> 803a827 > monitor_node(Node, false), 806,813c830 < do_wait_dist_start(Node, Appl, Name, < Nodes, PermittedNodes, S, Type); < {dist_ac_weight, Name1, Weight1, Node1} -> < %% UW 000310: Node1 is busy working on another app, and wants < %% to query us about weight. We must respond to avoid deadlock. < NewS = answer_weight(Name1, Weight1, Node1, S), < do_wait_dist_start(Node, Appl, Name, < Nodes, PermittedNodes, NewS, Type); --- > wait_dist_start(Node, Appl, Name, Nodes, PermittedNodes, S, Type); 817,822c834,838 < filter( < fun({Name2, _Weight, Node2}) when Node2 == Node, < Name2 == Name -> false; < (_) -> true < end, < S#state.tmp_locals), --- > filter(fun({Name2, _Weight, Node2}) when Node2 == Node, > Name2 == Name -> false; > (_) -> true > end, > S#state.tmp_locals), 836,841d851 < {dist_ac_weight, Name1, Weight1, Node1} -> < %% UW 000310: Node1 is busy working on another app, and wants < %% to query us about weight. We must respond to avoid deadlock. < NewS = answer_weight(Name1, Weight1, Node1, S), < wait_dist_start2(Appl, Name, < Nodes, PermittedNodes, NewS, Type); 1468,1498d1477 < %%% UW Patch 000310: This function is called from 3 different < %%% places (handle_info/2, do_wait_dist_start/7, and wait_dist_start2/6). < < answer_weight(Name, Weight, Node, S) -> < case keysearch(Name, #appl.name, S#state.appls) of < {value, Appl} -> < Id = Appl#appl.id, < case Id of < run_waiting -> < {?DIST_AC, Node} ! {dist_ac_weight, Name, 0, node()}, < S; < undefined -> < S#state{tmp_locals = [{Name, Weight, Node} | < S#state.tmp_locals]}; < {takeover, _} -> < S#state{tmp_locals = [{Name, Weight, Node} | < S#state.tmp_locals]}; < {failover, _} -> < S#state{tmp_locals = [{Name, Weight, Node} | < S#state.tmp_locals]}; < _ -> < MyWeight = get_cached_weight(Name, S), < {?DIST_AC, Node} ! < {dist_ac_weight, Name, MyWeight, node()}, < NTWs = keyreplaceadd(Name, 1, S#state.tmp_weights, < {Name, MyWeight}), < S#state{tmp_weights = NTWs} < end; < _ -> < S#state{tmp_locals = [{Name, Weight, Node} | S#state.tmp_locals]} < end. On Fri, 10 Mar 2000, Sean Hinde wrote: Sean>Thanks Uffe, Sean> Sean>Here is the trace for the two remaining nodes, I'll also bring in the Sean>commercial support guys and let you all know the outcome. Sean> Sean>> Could you call process_info(whereis(dist_ac)) and post the Sean>> result? You could also try Sean>> erlang:process_display(whereis(dist_ac), backtrace). Sean> Sean>Cheers, Sean>Sean Sean> Sean> -- Ulf Wiger, Chief Designer AXD 301 Ericsson Telecom AB tfn: +46 8 719 81 95 Varuv?gen 9, ?lvsj? mob: +46 70 519 81 95 S-126 25 Stockholm, Sweden fax: +46 8 719 43 44 -------------- next part -------------- %% ``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$ %% -module(dist_ac). -vsn('$Revision: /main/release/9'). -behaviour(gen_server). %% External exports -export([start_link/0, load_application/2, takeover_application/2, permit_application/2, permit_only_loaded_application/2]). -export([get_known_nodes/0]). %% Internal exports -export([init/1, handle_cast/2, handle_call/3, handle_info/2, terminate/2, send_timeout/3]). -export([info/0]). -import(lists, [zf/2, filter/2, map/2, foreach/2, foldl/3, mapfoldl/3, keysearch/3, keydelete/3, keyreplace/4, member/2]). -define(AC, application_controller). -define(DIST_AC, ?MODULE). -define(LOCK_ID, ?MODULE). %% This is the protocol version for the dist_ac protcol (between nodes) -define(vsn, 1). %%%----------------------------------------------------------------- %%% This module implements the default Distributed Applications %%% Controller. It is possible to write other controllers, when %%% the functionality in this module are not sufficient. %%% The process cooperates with the application_controller. %%%----------------------------------------------------------------- %%----------------------------------------------------------------- %% Naming conventions: %% Appl = #appl %% AppName = atom() %%----------------------------------------------------------------- -record(state, {appls = [], tmp_locals = [], remote_started = [], known = [], started = [], tmp_weights = [], dist_loaded = [], t_reqs = [], s_reqs = [], p_reqs = []}). %%----------------------------------------------------------------- %% appls = [#appl()] - these are the applications we control %% tmp_locals = [{AppName, Weight, node()}] - tmp, info part of %% application startup for some distrib appls, %% not yet handled. %% remote_started = [{Node, AppName}] - info on apps started before %% we were started %% known = [Node] - These are the nodes known to us %% started = [AppName] - An ordered list of started applications %% (reversed start order) %% tmp_weight = [{AppName, MyWeight}] - tmp, if we're forced to %% send a dist_ac_weight message before we're prepared to, %% we remember the weight we sent here, so we can use %% it in the dist_ac_weight msgs later. %% dist_loaded = {{Name, Node}, HisNodes, Permission} - info on %% application loaded on other nodes (and own node) %% t_reqs = [{AppName, From}] - processes waiting for takeover %% to complete. %% s_reqs = [{AppName, From}] - processes waiting for stop %% to complete. %% p_reqs = [{From, AppName, Bool, [Node]] - outstanding permit. %% Nodes is a list of nodes we're still waiting for. %%----------------------------------------------------------------- -record(appl, {name, id, restart_time = 0, nodes = [], run = []}). %%----------------------------------------------------------------- %% id = local | undefined | {distributed, node()} | waiting | run_waiting | %% {failover, Node} | {takeover, Node} %% local : local application %% undefined : not yet started %% {distributed, Node} : running on another node, we're standby %% {failover, Node} : failover from Node %% {takeover, Node} : takeover from Node %% waiting : other node went down, we're waiting for a timeout %% to takeover it. From = pid() | undefined %% run_waiting : we have decided to start the app; wait for the %% AC result %%----------------------------------------------------------------- start_link() -> case gen_server:start_link({local, ?DIST_AC}, ?MODULE, [], []) of {ok, Pid} -> gen_server:cast(?DIST_AC, init_sync), {ok, Pid}; Else -> Else end. %%----------------------------------------------------------------- %% Func: load_application(AppName, DistNodes) %% Args: AppName = atom() %% DistNodes = default | {AppName, Time, [node() | {node()...}]} %% Purpose: Notifies the dist_ac about distributed nodes for an %% application. DistNodes overrides the kernel 'distributed' %% parameter. %% Returns: ok | {error, Reason} %%----------------------------------------------------------------- load_application(AppName, DistNodes) -> gen_server:call(?DIST_AC, {load_application, AppName, DistNodes}, infinity). takeover_application(AppName, RestartType) -> case validRestartType(RestartType) of true -> wait_for_sync_dacs(), Nodes = get_nodes(AppName), global:trans( {?LOCK_ID, self()}, fun() -> gen_server:call( ?DIST_AC, {takeover_application, AppName, RestartType}, infinity) end, Nodes); false -> {error, {invalid_restart_type, RestartType}} end. %%----------------------------------------------------------------- %% This function controls which applications are permitted to run. If %% an application X runs when this function is called as %% permit_application(X, false), it is moved to another node where it %% is permitted to run (distributed applications only). If there is %% no such node, the application is stopped. (I.e. local applications %% are always stopped, and distributed applications with no other node %% alive are stopped as well.) If later a call to %% permit_application(X, true) is made, X is restarted. %% For example, suppose applications app1 and app2 are started and %% running. %% If we evaluate %% permit_application(app2, false) %% app2 is stopped and app1 only is running. %% If we now evaluate %% permit_application(app2, true), %% permit_application(app3, true) %% app2 is restarted, but not app3, since it hasn't been started by a %% call to start_application. %%----------------------------------------------------------------- permit_application(AppName, Bool) -> wait_for_sync_dacs(), Nodes = get_nodes(AppName), LockId = {?LOCK_ID, self()}, global:trans( LockId, fun() -> gen_server:call(?DIST_AC, {permit_application, AppName, Bool, LockId, started}, infinity) end). permit_only_loaded_application(AppName, Bool) -> wait_for_sync_dacs(), Nodes = get_nodes(AppName), LockId = {?LOCK_ID, self()}, global:trans( LockId, fun() -> gen_server:call(?DIST_AC, {permit_application, AppName, Bool, LockId, only_loaded}, infinity) end). get_nodes(AppName) -> gen_server:call(?DIST_AC, {get_nodes, AppName}, infinity). get_known_nodes() -> gen_server:call(?DIST_AC, get_known_nodes). %%%----------------------------------------------------------------- %%% call-back functions from gen_server %%%----------------------------------------------------------------- init([]) -> process_flag(trap_exit, true), {ok, #state{}}. sync_dacs(Appls) -> Res = global:trans({?LOCK_ID, sync_dacs}, fun() -> Nodes = introduce_me(nodes(), Appls), wait_dacs(Nodes, [node()], Appls, []) end), ets:insert(ac_tab, {sync_dacs, ok}), Res. introduce_me(Nodes, Appls) -> Msg = {dist_ac_new_node, ?vsn, node(), Appls, []}, filter(fun(Node) -> %% This handles nodes without DACs case rpc:call(Node, erlang, whereis, [?DIST_AC]) of Pid when pid(Pid) -> Pid ! Msg, true; _ -> false end end, Nodes). wait_dacs([Node | Nodes], KnownNodes, Appls, RStarted) -> monitor_node(Node, true), receive %% HisAppls /= [] is the case when our node connects to a running system %% %% It is always the responsibility of newer versions to understand %% older versions of the protocol. As we don't have any older %% versions (that are supposed to work with this version), we %% don't handle version mismatch here. {dist_ac_new_node, Vsn, Node, HisAppls, HisStarted} -> monitor_node(Node, false), NRStarted = RStarted ++ HisStarted, NAppls = dist_merge(Appls, HisAppls, Node), wait_dacs(Nodes, [Node | KnownNodes], NAppls, NRStarted); {nodedown, Node} -> monitor_node(Node, false), wait_dacs(Nodes, KnownNodes, Appls, RStarted) end; wait_dacs([], KnownNodes, Appls, RStarted) -> {KnownNodes, Appls, RStarted}. info() -> gen_server:call(?DIST_AC, info). %%----------------------------------------------------------------- %% All functions that can affect which applications are running %% execute within a global lock, to ensure that they are not %% executing at the same time as sync_dacs. However, to avoid a %% deadlock situation where e.g. permit_application gets the lock %% before sync_dacs, this function is used to ensure that the local %% sync_dacs always gets the lock first of all. The lock is still %% used to not interfere with sync_dacs on other nodes. %%----------------------------------------------------------------- wait_for_sync_dacs() -> case catch ets:lookup(ac_tab, sync_dacs) of [{sync_dacs, ok}] -> ok; _ -> receive after 100 -> ok end, wait_for_sync_dacs() end. handle_cast(init_sync, _S) -> %% When the dist_ac is started, it receives this msg, and gets into %% the receive loop. 'go' is sent from the kernel_config proc when %% all nodes that should be pinged has been pinged. The reason for this %% is that dist_ac syncs with the other nodes at start-up. That is, %% it does _not_ handle partitioned nets! The other nodes tries to call %% the local name dist_ac, which means that this name must be registered %% before the distribution. But it can't sync until after the distribution %% is started. Therefore, this 'go'-thing. receive go -> ok end, Appls = case application:get_env(kernel, distributed) of {ok, D} -> dist_check(D); undefined -> [] end, dist_take_control(Appls), net_kernel:monitor_nodes(true), % we're really just interested in nodedowns. {Known, NAppls, RStarted} = sync_dacs(Appls), {noreply, #state{appls = NAppls, known = Known, remote_started = RStarted}}. handle_call(info, _From, S) -> {reply, S, S}; handle_call({load_application, AppName, DistNodes}, _From, S) -> Appls = S#state.appls, case catch dist_replace(DistNodes, AppName, Appls) of {error, Error} -> {reply, {error, Error}, S}; {'EXIT', R} -> {stop, R, {error, R}, S}; NAppls -> NewS = case dist_find_nodes(NAppls, AppName) of [] -> % No distrib nodes; we ignore it S; _Nodes -> ensure_take_control(AppName, Appls), {ok, S2} = load(AppName, S#state{appls = NAppls}), S2 end, {reply, ok, NewS} end; handle_call({takeover_application, AppName, RestartType}, From, S) -> Appls = S#state.appls, case keysearch(AppName, #appl.name, Appls) of {value, Appl} when element(1, Appl#appl.id) == distributed -> {distributed, Node} = Appl#appl.id, ac_takeover(req, AppName, Node, RestartType), NAppl = Appl#appl{id = takeover}, NAppls = keyreplace(AppName, #appl.name, Appls, NAppl), TR = S#state.t_reqs, {noreply, S#state{appls = NAppls, t_reqs = [{AppName, From} | TR]}}; {value, #appl{id = local}} -> {reply, {error, {already_running_locally, AppName}}, S}; _ -> {reply, {error, {not_running_distributed, AppName}}, S} end; handle_call({permit_application, AppName, Bool, LockId, StartInfo}, From, S) -> case lists:keysearch(AppName, #appl.name, Appls = S#state.appls) of false -> %% This one covers the case with permit for non-distributed %% applications. This shouldn't be handled like this, and not %% here, but we have to be backwards-compatible. case application_controller:get_loaded(AppName) of {true, _} when Bool == false -> ac_stop_it(AppName), {reply, ok, S}; {true, _} when Bool == true -> ac_start_it(req, AppName), {reply, ok, S}; false -> {reply, {error, {not_loaded, AppName}}, S} end; {value, _} -> NAppls = dist_update_run(S#state.appls, AppName, node(), Bool), NewS = S#state{appls = NAppls}, %% Check if the application is running IsRunning = keysearch(AppName, #appl.name, NAppls), IsMyApp = case IsRunning of {value, #appl{id = local}} -> true; _ -> false end, %% Tell everyone about the new permission Nodes = dist_flat_nodes(NAppls, AppName), Msg = {dist_ac_new_permission, node(), AppName, Bool, IsMyApp}, send_msg(Msg, Nodes), case StartInfo of only_loaded -> {reply, ok, NewS}; started -> permit(Bool, IsRunning, AppName, From, NewS, LockId) end end; %%----------------------------------------------------------------- %% The distributed parameter is changed. Update the parameters %% but the applications are actually not moved to other nodes %% even if they should. %%----------------------------------------------------------------- handle_call({distribution_changed, NewDistribution}, _From, S) -> Appls = S#state.appls, NewAppls = dist_change_update(Appls, NewDistribution), NewS = S#state{appls = NewAppls}, {reply, ok, NewS}; handle_call({get_nodes, AppName}, _From, S) -> Alive = intersection(dist_flat_nodes(S#state.appls, AppName), S#state.known), {reply, Alive, S}; handle_call(get_known_nodes, _From, S) -> {reply, S#state.known, S}. handle_info({ac_load_application_req, AppName}, S) -> {ok, NewS} = load(AppName, S), ?AC ! {ac_load_application_reply, AppName, ok}, {noreply, NewS}; handle_info({ac_application_unloaded, AppName}, S) -> {ok, NewS} = unload(AppName, S), {noreply, NewS}; handle_info({ac_start_application_req, AppName}, S) -> %% We must decide if we or another node should start the application Lock = {?LOCK_ID, self()}, case global:set_lock(Lock, [node()], 1) of true -> S2 = case catch start_appl(AppName, S, reply) of {ok, NewS, _} -> NewS; {error, R} -> ?AC ! {ac_start_application_reply, AppName, {error,R}}, S end, global:del_lock(Lock), {noreply, S2}; false -> send_after(100, {ac_start_application_req, AppName}), {noreply, S} end; handle_info({ac_application_run, AppName, Res}, S) -> %% We ordered a start, and here's the result. Tell all other nodes. Appls = S#state.appls, Nodes = S#state.known, %% Send this to _all_ known nodes, as any node could sync %% on this app (not only nodes that can run it). send_msg({dist_ac_app_started, node(), AppName, Res}, Nodes), NId = case Res of ok -> local; {error, R} -> undefined end, {value, Appl} = keysearch(AppName, #appl.name, Appls), %% Check if we have somebody waiting for the takeover result NTReqs = del_t_reqs(AppName, S#state.t_reqs, Res), NAppl = Appl#appl{id = NId}, NAppls = keyreplace(AppName, #appl.name, Appls, NAppl), {noreply, S#state{appls = NAppls, t_reqs = NTReqs}}; handle_info({ac_application_not_run, AppName}, S) -> %% We ordered a stop, and now it has stopped {value, Appl} = keysearch(AppName, #appl.name, Appls = S#state.appls), %% Check if we have somebody waiting for the takeover result; %% if somebody called stop just before takeover was handled, NTReqs = del_t_reqs(AppName, S#state.t_reqs, {error, stopped}), %% Check if we have somebody waiting for stop to return SReqs = filter(fun({Name, From2}) when Name == AppName -> gen_server:reply(From2, ok), false; (_) -> true end, S#state.s_reqs), send_msg({dist_ac_app_stopped, AppName}, S#state.known), NAppl = Appl#appl{id = undefined}, NAppls = keyreplace(AppName, #appl.name, Appls, NAppl), {noreply, S#state{appls = NAppls, t_reqs = NTReqs, s_reqs = SReqs}}; handle_info({ac_application_stopped, AppName}, S) -> %% Somebody called application:stop - reset state as it was before %% the application was started. {value, Appl} = keysearch(AppName, #appl.name, Appls = S#state.appls), %% Check if we have somebody waiting for the takeover result; %% if somebody called stop just before takeover was handled, NTReqs = del_t_reqs(AppName, S#state.t_reqs, {error, stopped}), %% Check if we have somebody waiting for stop to return SReqs = filter(fun({Name, From2}) when Name == AppName -> gen_server:reply(From2, ok), false; (_) -> true end, S#state.s_reqs), send_msg({dist_ac_app_stopped, AppName}, S#state.known), NAppl = Appl#appl{id = undefined}, NAppls = keyreplace(AppName, #appl.name, Appls, NAppl), Started = lists:delete(AppName, S#state.started), {noreply, S#state{appls = NAppls, started = Started, t_reqs = NTReqs, s_reqs = SReqs}}; %%----------------------------------------------------------------- %% A new node gets running. %% Send him info about our started distributed applications. %%----------------------------------------------------------------- handle_info({dist_ac_new_node, Vsn, Node, HisAppls, []}, S) -> Appls = S#state.appls, MyStarted = zf(fun(Appl) when Appl#appl.id == local -> {true, {node(), Appl#appl.name}}; (_) -> false end, Appls), {?DIST_AC, Node} ! {dist_ac_new_node, ?vsn, node(), Appls, MyStarted}, NAppls = dist_merge(Appls, HisAppls, Node), {noreply, S#state{appls = NAppls, known = [Node | S#state.known]}}; handle_info({dist_ac_app_started, Node, Name, Res}, S) -> case lists:member(Name, S#state.started) of true -> Appls = S#state.appls, {value, Appl} = keysearch(Name, #appl.name, Appls), NId = case Appl#appl.id of _ when element(1, Res) == error -> %% Start of appl on some node failed. %% Set Id to undefined. That node will have %% to take some actions, e.g. reboot undefined; {distributed, _} -> %% Another node tookover from some node. Update %% appl list. {distributed, Node}; local -> %% Another node tookover from me; stop my application %% and update the running list. {distributed, Node}; _ -> %% Another node started appl. Update appl list. {distributed, Node} end, ac_started(req, Name, Node), NAppl = Appl#appl{id = NId}, NAppls = keyreplace(Name, #appl.name, Appls, NAppl), TmpWeights = keydelete_all(Name, 1, S#state.tmp_weights), NewS = S#state{appls = NAppls, tmp_weights = TmpWeights}, NPermitReq = req_del_permit_false(NewS#state.p_reqs, Name), case catch req_start_app(NewS#state{p_reqs = NPermitReq}, Name) of {error, R} -> {stop, R}; {ok, NewS2} -> {noreply, NewS2} end; false -> %% The app has not been started at this node yet; remember this in %% remote started. NRStarted = [{Node, Name} | S#state.remote_started], {noreply, S#state{remote_started = NRStarted}} end; handle_info({dist_ac_app_stopped, AppName}, S) -> {value, Appl} = keysearch(AppName, #appl.name, Appls = S#state.appls), NAppl = Appl#appl{id = undefined}, NAppls = keyreplace(AppName, #appl.name, Appls, NAppl), RStarted = keydelete(AppName, 2, S#state.remote_started), {noreply, S#state{appls = NAppls, remote_started = RStarted}}; handle_info({dist_ac_weight, Name, Weight, Node}, S) -> %% This means another node starts up, and will eventually take over %% this appl. We have a situation like: {Name, [{Node}, node()]} %% Node sends us this msg, and we must respond. It doesn't really %% matter what we send him; but it must be a dist_ac_weight msg. %% Another situation is {Name, [RNode, {node()}, Node]}. %% %% Yet another situation is that the node where Name was running crashed, %% and Node has got the nodedown message, but we haven't. In this case, %% we must send a correct weight to Node. i.e. the same weight that %% we'll send to him later, when we get the nodedown message. %% UW patch: broke out the code into its own function NewS = answer_weight(Name, Weight, Node, S), {noreply, NewS}; %%----------------------------------------------------------------- %% A node died. Check if we should takeover some applications. %%----------------------------------------------------------------- handle_info({nodedown, Node}, S) -> AppNames = dist_get_runnable(S#state.appls), HisAppls = filter(fun(#appl{name = Name, id = {distributed, N}}) when Node == N -> lists:member(Name, AppNames); (_) -> false end, S#state.appls), Appls2 = zf(fun(Appl) when Appl#appl.id == {distributed, Node} -> case lists:member(Appl#appl.name, AppNames) of true -> {true, Appl#appl{id = {failover, Node}}}; false -> ac_not_running(Appl#appl.name), {true, Appl#appl{id = undefined}} end; (_) -> true end, S#state.appls), RStarted = filter(fun({Node2, _Name}) when Node2 == Node -> false; (_) -> true end, S#state.remote_started), Appls3 = dist_del_node(Appls2, Node), {NPermitReq, Appls4, SReqs} = req_del_node(S, Node, Appls3), NKnown = lists:delete(Node, S#state.known), NewS = S#state{appls = Appls4, p_reqs = NPermitReq, known = NKnown, s_reqs = SReqs, remote_started = RStarted}, restart_appls(HisAppls), {noreply, NewS}; handle_info({dist_ac_app_loaded, Node, Name, HisNodes, Permission, HeKnowsMe}, S) -> Nodes = dist_find_nodes(Appls = S#state.appls, Name), case is_loaded(Name, S) of true -> case equal_nodes(Nodes, HisNodes) of true -> NAppls = dist_update_run(Appls, Name, Node, Permission), if HeKnowsMe == false -> %% We've got it loaded, but he doesn't know - %% he's a new node connecting to us. Msg = {dist_ac_app_loaded, node(), Name, Nodes, dist_is_runnable(Appls, Name), true}, {?DIST_AC, Node} ! Msg; true -> ok end, {noreply, S#state{appls = NAppls}}; false -> exit({distribution_mismatch, Name, Node}) end; false -> Load =[{{Name, Node}, HisNodes, Permission} | S#state.dist_loaded], {noreply, S#state{dist_loaded = Load}} end; handle_info({dist_ac_app_unloaded, Node, Name}, S) -> Appls = dist_update_run(S#state.appls, Name, Node, undefined), Load = keydelete({Name, Node}, 1, S#state.dist_loaded), {noreply, S#state{appls = Appls, dist_loaded = Load}}; handle_info({dist_ac_new_permission, Node, AppName, false, IsHisApp}, S) -> Appls = dist_update_run(S#state.appls, AppName, Node, false), NewS = S#state{appls =Appls}, case dist_is_runnable(Appls, AppName) of true when IsHisApp == true -> case catch start_appl(AppName, NewS, req) of {ok, NewS2, _} -> {noreply, NewS2}; {error, R} -> % if app was permanent, AC will shutdown the node {noreply, NewS} end; _ -> {noreply, NewS} end; handle_info({dist_ac_new_permission, Node, AppName, true, _IsHisApp}, S) -> Appls = dist_update_run(S#state.appls, AppName, Node, true), {noreply, S#state{appls = Appls}}; handle_info({internal_restart_appl, Name}, S) -> case restart_appl(Name, S) of {error, R} -> {stop, {error, R}, S}; NewS -> {noreply, NewS} end; handle_info(_, S) -> {noreply, S}. terminate(Reason, S) -> ok. %%%----------------------------------------------------------------- %%% Internal functions %%%----------------------------------------------------------------- load(AppName, S) -> Appls0 = S#state.appls, %% Get the dist specification for the app on other nodes DistLoaded = get_dist_loaded(AppName, Load1 = S#state.dist_loaded), %% Get the local dist specification Nodes = dist_find_nodes(Appls0, AppName), FNodes = flat_nodes(Nodes), %% Update dists spec with our local permission Permission = get_default_permission(AppName), Appls1 = dist_update_run(Appls0, AppName, node(), Permission), %% Compare the local spec with other nodes's specs %% If equal, update our spec with his current permission {LoadedNodes, Appls2} = mapfoldl( fun({Node, HisNodes, HisPermission}, Appls) -> case equal_nodes(Nodes, HisNodes) of true -> {Node, dist_update_run(Appls, AppName, Node, HisPermission)}; _ -> exit({distribution_mismatch, AppName, Node}) end end, Appls1, DistLoaded), Load2 = del_dist_loaded(AppName, Load1), %% Tell all Nodes about the new appl loaded, and its permission. foreach(fun(Node) when Node /= node() -> Msg = {dist_ac_app_loaded, node(), AppName, Nodes, Permission, member(Node, LoadedNodes)}, {?DIST_AC, Node} ! Msg; (_) -> ok end, FNodes), {ok, S#state{appls = Appls2, dist_loaded = Load2}}. ensure_take_control(AppName, Appls) -> %% Check if this is a new application that we don't control yet case keysearch(AppName, #appl.name, Appls) of {value, _} -> % we have control ok; false -> % take control! %% Note: this works because this is executed within a %% synchronous call. I.e. we get the control *before* %% application:load returns. (otherwise application:start %% could be called before we got the chance to take control) %% The only reason we have to bother about this is because %% we have to be backwards compatible in the sense that all %% apps don't have to be specified in the 'distributed' parameter, %% but may be implicitly 'distributed' by a call to %% application:load. application_controller:control_application(AppName) end. unload(AppName, S) -> Appls = S#state.appls, Nodes = dist_flat_nodes(Appls, AppName), %% Tell all ACs in DistNodes about the unloaded appl Msg = {dist_ac_app_unloaded, node(), AppName}, send_msg(Msg, Nodes), {value, Appl} = keysearch(AppName, #appl.name, Appls), NAppl = Appl#appl{id = undefined, run = []}, {ok, S#state{appls = keyreplace(AppName, #appl.name, Appls, NAppl)}}. start_appl(AppName, S, Type) -> %% Get nodes, and check if App is loaded on all involved nodes. %% If it is loaded everywhere, we know that we have the same picture %% of the nodes; otherwise the load wouldn't have succeeded. {value, Appl} = keysearch(AppName, #appl.name, Appls = S#state.appls), case Appl#appl.id of local -> %% UW 990913: we've already started the app %% this could happen if ac_start_application_req was resent. {ok,S,false}; _ -> {Id, IsWaiting} = case dist_get_all_nodes(Appl) of {ok, DistNodes, PermittedNodes} -> start_distributed(Appl, AppName, DistNodes, PermittedNodes, S, Type); Error -> throw(Error) end, NAppl = Appl#appl{id = Id}, NAppls = keyreplaceadd(AppName, #appl.name, Appls, NAppl), {ok, NewS} = req_start_app(S#state{appls = NAppls}, AppName), TmpLocals = keydelete_all(AppName, 1, NewS#state.tmp_locals), TmpWeights = keydelete_all(AppName, 1, NewS#state.tmp_weights), RStarted = keydelete(AppName, 2, S#state.remote_started), Started = replaceadd(AppName, NewS#state.started), {ok, NewS#state{started = Started, tmp_locals = TmpLocals, tmp_weights = TmpWeights, remote_started = RStarted}, IsWaiting} end. start_distributed(Appl, Name, Nodes, PermittedNodes, S, Type) -> case find_start_node(Nodes, PermittedNodes, Name, S) of {ok, Node} when Node == node() -> case Appl#appl.id of {failover, FoNode} when Type == req -> ac_failover(Name, FoNode, undefined); {distributed, Node2} when Type == req -> ac_takeover(req, Name, Node2, undefined); _ when Type == reply -> case lists:keysearch(Name, 2, S#state.remote_started) of {value, {Node3, _}} -> ac_takeover(reply, Name, Node3, undefined); _ -> ac_start_it(Type, Name) end; _ -> ac_start_it(Type, Name) end, {run_waiting, true}; {already_started, Node} -> ac_started(Type, Name, Node), {{distributed, Node}, false}; {ok, Node} -> case keysearch(Name, #appl.name, S#state.appls) of {value, #appl{id = {distributed, Node}}} -> ac_started(Type, Name, Node), {{distributed, Node}, false}; _ -> wait_dist_start(Node, Appl, Name, Nodes, PermittedNodes, S, Type) end; not_started -> wait_dist_start2(Appl, Name, Nodes, PermittedNodes, S, Type); no_permission -> ac_not_started(Type, Name), {undefined, false} end. wait_dist_start(Node, Appl, Name, Nodes, PermittedNodes, S, Type) -> monitor_node(Node, true), do_wait_dist_start(Node, Appl, Name, Nodes, PermittedNodes, S, Type). do_wait_dist_start(Node, Appl, Name, Nodes, PermittedNodes, S, Type) -> receive {dist_ac_app_started, Node, Name, ok} -> ac_started(Type, Name, Node), monitor_node(Node, false), {{distributed, Node}, false}; {dist_ac_app_started, Node, Name, {error, R}} -> ac_error(Type, Name, {Node, R}), monitor_node(Node, false), {Appl#appl.id, false}; {dist_ac_weight, Name, _Weigth, Node} -> %% This is the situation: {Name, [RNode, {Node}, node()]} %% and permit(false) is called on RNode, and we sent the %% weigth first. Node handled it in handle_info, and %% now we must send him a weigth msg. We can use any weigth; %% he wins anyway. {?DIST_AC, Node} ! {dist_ac_weight, Name, get_cached_weight(Name, S), node()}, do_wait_dist_start(Node, Appl, Name, Nodes, PermittedNodes, S, Type); {dist_ac_weight, Name1, Weight1, Node1} -> %% UW 000310: Node1 is busy working on another app, and wants %% to query us about weight. We must respond to avoid deadlock. NewS = answer_weight(Name1, Weight1, Node1, S), do_wait_dist_start(Node, Appl, Name, Nodes, PermittedNodes, NewS, Type); {nodedown, Node} -> monitor_node(Node, false), TmpLocals = filter( fun({Name2, _Weight, Node2}) when Node2 == Node, Name2 == Name -> false; (_) -> true end, S#state.tmp_locals), NewS = S#state{tmp_locals = TmpLocals}, start_distributed(Appl, Name, Nodes, lists:delete(Node, PermittedNodes), NewS, Type) end. wait_dist_start2(Appl, Name, Nodes, PermittedNodes, S, Type) -> receive {dist_ac_app_started, Node, Name, ok} -> ac_started(Type, Name, Node), {{distributed, Node}, false}; {dist_ac_app_started, Node, Name, {error, R}} -> ac_error(Type, Name, {Node, R}), {Appl#appl.id, false}; {dist_ac_weight, Name1, Weight1, Node1} -> %% UW 000310: Node1 is busy working on another app, and wants %% to query us about weight. We must respond to avoid deadlock. NewS = answer_weight(Name1, Weight1, Node1, S), wait_dist_start2(Appl, Name, Nodes, PermittedNodes, NewS, Type); {nodedown, Node} -> %% A node went down, try to start the app again - there may not %% be any more nodes to wait for. TmpLocals = filter(fun({Name2, _Weight, Node2}) when Node2 == Node, Name2 == Name -> false; (_) -> true end, S#state.tmp_locals), NewS = S#state{tmp_locals = TmpLocals}, start_distributed(Appl, Name, Nodes, lists:delete(Node, PermittedNodes), NewS, Type) end. ac_start_it(reply, Name) -> ?AC ! {ac_start_application_reply, Name, start_it}; ac_start_it(req, Name) -> ?AC ! {ac_change_application_req, Name, start_it}. ac_started(reply, Name, Node) -> ?AC ! {ac_start_application_reply, Name, {started, Node}}; ac_started(req, Name, Node) -> ?AC ! {ac_change_application_req, Name, {started, Node}}. ac_error(reply, Name, Error) -> ?AC ! {ac_start_application_reply, Name, {error, Error}}; ac_error(req, Name, Error) -> ok. ac_not_started(reply, Name) -> ?AC ! {ac_start_application_reply, Name, not_started}; ac_not_started(req, Name) -> ?AC ! {ac_change_application_req, Name, stop_it}. ac_stop_it(Name) -> ?AC ! {ac_change_application_req, Name, stop_it}. ac_takeover(reply, Name, Node, RestartType) -> ?AC ! {ac_start_application_reply, Name, {takeover, Node}}; ac_takeover(req, Name, Node, RestartType) -> ?AC ! {ac_change_application_req, Name, {takeover, Node, RestartType}}. ac_failover(Name, Node, RestartType) -> ?AC ! {ac_change_application_req, Name, {failover, Node, RestartType}}. ac_not_running(Name) -> ?AC ! {ac_change_application_req, Name, not_running}. restart_appls(Appls) -> foreach(fun(Appl) -> AppName = Appl#appl.name, send_after(Appl#appl.restart_time, {internal_restart_appl, AppName}) end, lists:reverse(Appls)). restart_appl(AppName, S) -> case keysearch(AppName, #appl.name, S#state.appls) of {value, Appl} when element(1, Appl#appl.id) == failover -> case catch start_appl(AppName, S, req) of {ok, NewS, _} -> NewS; {error, R} -> error_logger:error_msg(R), S end; _ -> S end. %% permit(ShouldBeRunning, IsRunning, ...) permit(false, {value, #appl{id = undefined}}, AppName, From, S, LockId) -> {reply, ok, S}; % It's not running permit(false, {value, #appl{id = Id}}, _AppName, _From, S, LockId) when element(1, Id) == distributed -> %% It is running at another node already {reply, ok, S}; permit(false, {value, _}, AppName, From, S, LockId) -> %% It is a distributed application %% Check if there is any runnable node case dist_get_runnable_nodes(S#state.appls, AppName) of [] -> %% There is no runnable node; stop application ac_stop_it(AppName), SReqs = [{AppName, From} | S#state.s_reqs], {noreply, S#state{s_reqs = SReqs}}; Nodes -> %% Delete all outstanding 'permit true' requests. PR = req_del_permit_true(S#state.p_reqs, AppName), NPReqs = [{From, AppName, false, Nodes} | PR], {noreply, S#state{p_reqs = NPReqs}} end; permit(true, {value, #appl{id = local}}, AppName, From, S, LockId) -> {reply, ok, S}; permit(true, _, AppName, From, S, LockId) -> case catch start_appl(AppName, S, req) of {_ErrorTag, {not_running, App}} -> %% Delete all outstanding 'permit false' requests PR = req_del_permit_false(S#state.p_reqs, AppName), NPReqs = [{false, AppName, true, App} | PR], {reply, ok, S#state{p_reqs = NPReqs}}; {ok, NewS, true} -> %% We have ordered a start or a takeover; we must not return %% until the app is running. TR = NewS#state.t_reqs, %% Delete the lock, so others may start the app global:del_lock(LockId), {noreply, NewS#state{t_reqs = [{AppName, From} | TR]}}; {ok, NewS, false} -> {reply, ok, S}; {_ErrorTag, R} -> {stop, R, {error, R}, S} end. do_start_appls(StartApps, S) -> SortedStartApps = StartApps, Appls = S#state.appls, {ok, foldl( fun(AppName, NewS) -> case catch start_appl(AppName, NewS, req) of {error, R} -> throw({{error, NewS}, R}); {ok, NewS2, _} -> NewS2 end end, S#state{appls = Appls}, lists:reverse(SortedStartApps))}. %%----------------------------------------------------------------- %% Nodes = [node() | {node(), ..., node()}] %% A list in priority order. If it is a tuple, we may pick any of %% them. This decision is made by all nodes in the list, and all %% nodes choose the same. This is accomplished in the following %% way: all Nodes send to all others a msg which tells how many %% applications each node has started. The one with least no of %% appls starts this one. %%----------------------------------------------------------------- find_start_node(Nodes, PermittedNodes, Name, S) -> AllNodes = intersection(flat_nodes(Nodes), PermittedNodes), case lists:member(node(), AllNodes) of true -> Weight = get_cached_weight(Name, S), find_start_node(Nodes, Name, S, Weight, AllNodes); false -> case keysearch(Name, 2, S#state.remote_started) of {value, {Node, _Name}} -> {already_started, Node}; _ when AllNodes /= [] -> not_started; _ -> no_permission end end. find_start_node([AnyNodes | Nodes], Name, S, Weight, AllNodes) when tuple(AnyNodes) -> case find_any_node(tuple_to_list(AnyNodes), Name, S, Weight, AllNodes) of false -> find_start_node(Nodes, Name, S, Weight, AllNodes); Res -> Res end; find_start_node([Node | Nodes], Name, S, Weight, AllNodes) -> case lists:member(Node, AllNodes) of true -> case keysearch(Name, #appl.name, S#state.appls) of {value, #appl{id = {distributed, Node}}} -> {already_started, Node}; _ -> case keysearch(Name, 2, S#state.remote_started) of {value, {Node, _Name}} -> {already_started, Node}; _ -> {ok, Node} end end; false -> find_start_node(Nodes, Name, S, Weight, AllNodes) end; find_start_node([], _Name, _S, _Weight, _AllNodes) -> not_started. %%----------------------------------------------------------------- %% First of all, check if the application is already running %% somewhere in AnyNodes; in that case we shall not move it! %%----------------------------------------------------------------- find_any_node(AnyNodes, Name, S, Weight, AllNodes) -> case check_running(Name, S, intersection(AnyNodes, AllNodes)) of {already_started, Node} -> {already_started, Node}; false -> %% Synchronize with all other nodes. send_nodes(AllNodes, {dist_ac_weight, Name, Weight, node()}), Answers = [{Weight, node()} | collect_answers(AllNodes, Name, S, [])], %% Make a decision (the same at every node) (smallest weight wins) find_alive_node(lists:sort(Answers), intersection(AnyNodes, S#state.known)) end. %%----------------------------------------------------------------- %% Check if another node started the appl before we got alive. %% If so, check if the node is one of AnyNodes. %%----------------------------------------------------------------- check_running(Name, #state{remote_started = RStarted, appls = Appls}, AnyNodes) -> case keysearch(Name, 2, RStarted) of {value, {Node, _Name}} -> case lists:member(Node, AnyNodes) of true -> {already_started, Node}; false -> false end; false -> case keysearch(Name, #appl.name, Appls) of {value, #appl{id = {distributed, Node}}} -> case lists:member(Node, AnyNodes) of true -> {already_started, Node}; false -> false end; _ -> false end end. find_alive_node([{_, Node} | Nodes], AliveNodes) -> case lists:member(Node, AliveNodes) of true -> {ok, Node}; false -> find_alive_node(Nodes, AliveNodes) end; find_alive_node([], _AliveNodes) -> false. %%----------------------------------------------------------------- %% First, check if the node's msg is buffered (received in our %% main loop). Otherwise, wait for msg or nodedown. %% We have sent the dist_ac_weight message, and will wait for it %% to be received here (or a nodedown). This implies that a %% dist_ac must *always* be prepared to get this messages, and to %% send it to us. %%----------------------------------------------------------------- collect_answers([Node | Nodes], Name, S, Res) when Node /= node() -> case keysearch(Node, 3, S#state.tmp_locals) of {value, {Name, Weight, Node}} -> collect_answers(Nodes, Name, S, [{Weight, Node} | Res]); _ -> monitor_node(Node, true), receive {dist_ac_weight, Name, Weight, Node} -> monitor_node(Node, false), collect_answers(Nodes, Name, S, [{Weight, Node} | Res]); {nodedown, Node} -> monitor_node(Node, false), collect_answers(Nodes, Name, S, Res) end end; collect_answers([Node | Nodes], Name, S, Res) -> collect_answers(Nodes, Name, S, Res); collect_answers([], _Name, _S, Res) -> Res. send_nodes(Nodes, Msg) -> FlatNodes = flat_nodes(Nodes), foreach(fun(Node) when Node /= node() -> {?DIST_AC, Node} ! Msg; (Node) -> ok end, FlatNodes). send_after(Time, Msg) when integer(Time), Time >= 0 -> spawn_link(?MODULE, send_timeout, [self(), Time, Msg]); send_after(_,_) -> % infinity ok. send_timeout(To, Time, Msg) -> receive after Time -> To ! Msg end. send_msg(Msg, Nodes) -> foreach(fun(Node) when Node /= node() -> {?DIST_AC, Node} ! Msg; (_) -> ok end, Nodes). replaceadd(Item, List) -> case member(Item, List) of true -> List; false -> [Item | List] end. keyreplaceadd(Key, Pos, List, New) -> case keysearch(Key, Pos, List) of {value, _} -> keyreplace(Key, Pos, List, New); _ -> [New | List] end. keydelete_all(Key, N, [H|T]) when element(N, H) == Key -> keydelete_all(Key, N, T); keydelete_all(Key, N, [H|T]) -> [H|keydelete_all(Key, N, T)]; keydelete_all(Key, N, []) -> []. -ifdef(NOTUSED). keysearchdelete(Key, Pos, List) -> ksd(Key, Pos, List, []). ksd(Key, Pos, [H | T], Rest) when element(Pos, H) == Key -> {value, H, Rest ++ T}; ksd(Key, Pos, [H | T], Rest) -> ksd(Key, Pos, T, [H | Rest]); ksd(_Key, _Pos, [], _Rest) -> false. get_new_appl(Name, [{application, Name, App} | _]) -> {ok, {application, Name, App}}; get_new_appl(Name, [_ | T]) -> get_new_appl(Name, T); get_new_appl(Name, []) -> false. -endif. equal_nodes([H | T1], [H | T2]) when atom(H) -> equal_nodes(T1, T2); equal_nodes([H1 | T1], [H2 | T2]) when tuple(H1), tuple(H2) -> case equal(tuple_to_list(H1), tuple_to_list(H2)) of true -> equal_nodes(T1, T2); false -> false end; equal_nodes([], []) -> true; equal_nodes(_, _) -> false. equal([H | T] , S) -> case lists:member(H, S) of true -> equal(T, lists:delete(H, S)); false -> false end; equal([], []) -> true; equal(_, _) -> false. flat_nodes(Nodes) when list(Nodes) -> foldl(fun(Node, Res) when atom(Node) -> [Node | Res]; (Tuple, Res) when tuple(Tuple) -> tuple_to_list(Tuple) ++ Res end, [], Nodes); flat_nodes(Nodes) -> throw({error, {badarg, Nodes}}). get_cached_weight(Name, S) -> case lists:keysearch(Name, 1, S#state.tmp_weights) of {value, {_, W}} -> W; _ -> get_weight() end. %% Simple weight; just count the number of applications running. get_weight() -> length(application:which_applications()). get_dist_loaded(Name, [{{Name, Node}, HisNodes, Permission} | T]) -> [{Node, HisNodes, Permission} | get_dist_loaded(Name, T)]; get_dist_loaded(Name, [H | T]) -> get_dist_loaded(Name, T); get_dist_loaded(Name, []) -> []. del_dist_loaded(Name, [{{Name, Node}, HisNodes, Permission} | T]) -> del_dist_loaded(Name, T); del_dist_loaded(Name, [H | T]) -> [H | del_dist_loaded(Name, T)]; del_dist_loaded(Name, []) -> []. req_start_app(State, Name) -> {ok, foldl( fun({false, AppName, true, Name2}, S) when Name == Name2 -> PR = keydelete(AppName, 2, S#state.p_reqs), NS = S#state{p_reqs = PR}, case catch do_start_appls([AppName], NS) of {_ErrorTag, {not_running, App}} -> NRequests = [{false, AppName, true, App} | PR], S#state{p_reqs = NRequests}; {ok, NewS} -> NewS; {_ErrorTag, R} -> throw({error, R}) end; (_, S) -> S end, State, State#state.p_reqs)}. req_del_permit_true(Reqs, Name) -> filter(fun({From, Name2, true, _}) when Name2 == Name -> gen_server:reply(From, ok), false; (_) -> true end, Reqs). req_del_permit_false(Reqs, Name) -> filter(fun({From, Name2, false, _Nodes}) when Name2 == Name -> gen_server:reply(From, ok), false; (_) -> true end, Reqs). req_del_node(S, Node, Appls) -> check_waiting(S#state.p_reqs, S, Node, Appls, [], S#state.s_reqs). del_t_reqs(AppName, TReqs, Res) -> lists:filter(fun({AN, From}) when AppName == AN -> gen_server:reply(From, Res), false; (_) -> true end, TReqs). check_waiting([{From, AppName, false, Nodes} | Reqs], S, Node, Appls, Res, SReqs) -> case lists:delete(Node, Nodes) of [] -> ac_stop_it(AppName), NSReqs = [{AppName, From} | SReqs], check_waiting(Reqs, Node, S, Appls, Res, NSReqs); NNodes -> check_waiting(Reqs, Node, S, Appls, [{From, AppName, false, NNodes} | Res], SReqs) end; check_waiting([H | Reqs], S, Node, Appls, Res, SReqs) -> check_waiting(Reqs, Node, S, Appls, [H | Res], SReqs); check_waiting([], Node, S, Appls, Res, SReqs) -> {Res, Appls, SReqs}. intersection(Nodes1, Nodes2) -> Nodes1 -- (Nodes1 -- Nodes2). get_default_permission(AppName) -> case application:get_env(kernel, permissions) of {ok, Permissions} -> case keysearch(AppName, 1, Permissions) of {value, {_, true}} -> true; {value, {_, false}} -> false; {value, {_, X}} -> exit({bad_permission, {AppName, X}}); false -> true end; undefined -> true end. %%----------------------------------------------------------------- %% ADT dist() - info on how an application is distributed %% dist() = [{AppName, Time, DistNodes, [{Node, Runnable}]}] %% Time = int() >= 0 | infinity %% Nodes = [node() | {node()...}] %% Runnable = true | false | undefined %% An appl may not be started if any Runnable is undefined; %% i.e. the appl must be loaded on all Nodes. %%----------------------------------------------------------------- dist_check([{AppName, Nodes} | T]) -> P = get_default_permission(AppName), [#appl{name = AppName, nodes = Nodes, run = [{node(), P}]} | dist_check(T)]; dist_check([{AppName, Time, Nodes} | T]) when integer(Time), Time >= 0 -> P = get_default_permission(AppName), [#appl{name = AppName, restart_time = Time, nodes = Nodes, run = [{node(), P}]} | dist_check(T)]; dist_check([{AppName, infinity, Nodes} | T]) -> P = get_default_permission(AppName), [#appl{name = AppName, restart_time = infinity, nodes = Nodes, run = [{node(), P}]} | dist_check(T)]; dist_check([_ | T]) -> dist_check(T); dist_check([]) -> []. dist_take_control(Appls) -> foreach(fun(#appl{name = AppName}) -> application_controller:control_application(AppName) end, Appls). dist_replace(default, _Name, Appls) -> Appls; dist_replace({AppName, Nodes}, AppName, Appls) -> Run = map(fun(Node) -> {Node, undefined} end, flat_nodes(Nodes)), keyreplaceadd(AppName, #appl.name, Appls, #appl{name = AppName, restart_time = 0, nodes = Nodes, run = Run}); dist_replace({AppName, Time, Nodes}, AppName, Appls) when integer(Time), Time >= 0 -> Run = map(fun(Node) -> {Node, undefined} end, flat_nodes(Nodes)), keyreplaceadd(AppName, #appl.name, Appls, #appl{name = AppName, restart_time = Time, nodes = Nodes, run = Run}); dist_replace(Bad, _Name, _Appls) -> throw({error, {bad_distribution_spec, Bad}}). dist_update_run(Appls, AppName, Node, Permission) -> map(fun(Appl) when Appl#appl.name == AppName -> Run = Appl#appl.run, NRun = keyreplaceadd(Node, 1, Run, {Node, Permission}), Appl#appl{run = NRun}; (Appl) -> Appl end, Appls). dist_change_update(Appls, []) -> Appls; dist_change_update(Appls, [{AppName, NewNodes} | NewDist]) -> NewAppls = do_dist_change_update(Appls, AppName, 0, NewNodes), dist_change_update(NewAppls, NewDist); dist_change_update(Appls, [{AppName, NewTime, NewNodes} | NewDist]) -> NewAppls = do_dist_change_update(Appls, AppName, NewTime, NewNodes), dist_change_update(NewAppls, NewDist). do_dist_change_update(Appls, AppName, NewTime, NewNodes) -> map(fun(Appl) when Appl#appl.name == AppName -> Appl#appl{restart_time = NewTime, nodes = NewNodes}; (Appl) -> Appl end, Appls). %% Merge his Permissions with mine. dist_merge(MyAppls, HisAppls, HisNode) -> zf(fun(Appl) -> #appl{name = AppName, nodes = Nodes, run = Run} = Appl, % HeIsMember = lists:member(HisNode, flat_nodes(Nodes)), HeIsMember = true, case keysearch(AppName, #appl.name, HisAppls) of {value, #appl{run = HisRun}} when HeIsMember == true -> case keysearch(HisNode, 1, HisRun) of {value, Val} -> % He has it loaded NRun = keyreplaceadd(HisNode, 1, Run, Val), {true, Appl#appl{run = NRun}}; false -> % He hasn't loaded it yet Val = {HisNode, undefined}, {true, Appl#appl{run = [Val | Run]}} end; _ -> true end end, MyAppls). dist_get_runnable_nodes(Appls, AppName) -> case keysearch(AppName, #appl.name, Appls) of {value, #appl{run = Run}} -> zf(fun({Node, true}) -> {true, Node}; (_) -> false end, Run); false -> [] end. dist_is_runnable(Appls, AppName) -> case keysearch(AppName, #appl.name, Appls) of {value, #appl{run = Run}} -> case keysearch(node(), 1, Run) of {value, {_, true}} -> true; _ -> false end; false -> false end. is_loaded(AppName, #state{appls = Appls}) -> case keysearch(AppName, #appl.name, Appls) of {value, #appl{run = Run}} -> case keysearch(node(), 1, Run) of {value, {_Node, undefined}} -> false; {value, _} -> true; false -> false end; false -> false end. dist_get_runnable(Appls) -> zf(fun(#appl{name = AppName, run = Run}) -> case keysearch(node(), 1, Run) of {value, {_, true}} -> {true, AppName}; _ -> false end end, Appls). dist_get_all_nodes(#appl{name = AppName, nodes = Nodes, run = Run}) -> case check_nodes(Run, [], []) of {Res, []} -> {ok, Nodes, Res}; {_Res, BadNodes} -> {error, {app_not_loaded, AppName, BadNodes}} end. check_nodes([{Node, undefined} | T], Res, BadNodes) -> check_nodes(T, Res, [Node | BadNodes]); check_nodes([{Node, true} | T], Res, BadNodes) -> check_nodes(T, [Node | Res], BadNodes); check_nodes([{Node, false} | T], Res, BadNodes) -> check_nodes(T, Res, BadNodes); check_nodes([], Res, BadNodes) -> {Res, BadNodes}. -ifdef(NOTUSED). dist_find_time([#appl{name = Name, restart_time = Time} |_], Name) -> Time; dist_find_time([_ | T], Name) -> dist_find_time(T, Name); dist_find_time([], Name) -> 0. -endif. %% Find all nodes that can run the app (even if they're not permitted %% to right now). dist_find_nodes([#appl{name = Name, nodes = Nodes} |_], Name) -> Nodes; dist_find_nodes([_ | T], Name) -> dist_find_nodes(T, Name); dist_find_nodes([], Name) -> []. dist_flat_nodes(Appls, Name) -> flat_nodes(dist_find_nodes(Appls, Name)). dist_del_node(Appls, Node) -> map(fun(Appl) -> NRun = filter(fun({N, _Runnable}) when N == Node -> false; (_) -> true end, Appl#appl.run), Appl#appl{run = NRun}; (X) -> X end, Appls). validRestartType(permanent) -> true; validRestartType(temporary) -> true; validRestartType(transient) -> true; validRestartType(RestartType) -> false. %%% UW Patch 000310: This function is called from 3 different %%% places (handle_info/2, do_wait_dist_start/7, and wait_dist_start2/6). answer_weight(Name, Weight, Node, S) -> case keysearch(Name, #appl.name, S#state.appls) of {value, Appl} -> Id = Appl#appl.id, case Id of run_waiting -> {?DIST_AC, Node} ! {dist_ac_weight, Name, 0, node()}, S; undefined -> S#state{tmp_locals = [{Name, Weight, Node} | S#state.tmp_locals]}; {takeover, _} -> S#state{tmp_locals = [{Name, Weight, Node} | S#state.tmp_locals]}; {failover, _} -> S#state{tmp_locals = [{Name, Weight, Node} | S#state.tmp_locals]}; _ -> MyWeight = get_cached_weight(Name, S), {?DIST_AC, Node} ! {dist_ac_weight, Name, MyWeight, node()}, NTWs = keyreplaceadd(Name, 1, S#state.tmp_weights, {Name, MyWeight}), S#state{tmp_weights = NTWs} end; _ -> S#state{tmp_locals = [{Name, Weight, Node} | S#state.tmp_locals]} end. From Sean.Hinde@REDACTED Fri Mar 10 16:53:54 2000 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Fri, 10 Mar 2000 15:53:54 -0000 Subject: Distributed applications (global) Message-ID: > Sean, > > I've made a hack to the dist_ac.erl module. I haven't tried it, > mind you, but it does compile. I thought you'd like to try it. > What I've done is to try to make sure that dist_ac will always > respond to the {dist_ac_weight, _, _, _} messages. > > /Uffe That seems to have done the trick. One app starts on each of the remaining two nodes. I can't imagine that no-one has tried to have two apps failover in this simple config before though. It seems pretty fundamental. Any comment from the OTP guys? Thanks again, Sean From vladdu@REDACTED Tue Mar 14 09:48:44 2000 From: vladdu@REDACTED (Vlad Dumitrescu) Date: Tue, 14 Mar 2000 09:48:44 CET Subject: wonderings Message-ID: <20000314084844.27662.qmail@hotmail.com> Hi all! While being away for some time (away from the PC - what a nightmare!), I have been thinking a little. The Erlang book and the documentation are great, but I now feel that a book about the Erlang libraries and the OTP libraries would be very helpful. More detailed explanations and examples would make life much easier! Are there any plans? Or maybe there already is such a book? Does anyone else think it's a good idea? regards, Vlad ______________________________________________________ Get Your Private, Free Email at http://www.hotmail.com From Matthias.Lang@REDACTED Tue Mar 14 19:59:32 2000 From: Matthias.Lang@REDACTED (Matthias.Lang@REDACTED) Date: Tue, 14 Mar 2000 19:59:32 +0100 (MET) Subject: wonderings In-Reply-To: <20000314084844.27662.qmail@hotmail.com> References: <20000314084844.27662.qmail@hotmail.com> Message-ID: <14542.35860.503099.145784@gargle.gargle.HOWL> > The Erlang book and the documentation are great, but I now feel that a book > about the Erlang libraries and the OTP libraries would be very > helpful. > More detailed explanations and examples would make life much easier! > > Are there any plans? Or maybe there already is such a book? Does > anyone else think it's a good idea? I'd love to be able to buy a really neat, well-written book about more advanced Erlang topics. I'd also love to get a monthly newsletter-style thing with nice Erlang ideas, along the lines of the C++ report. Such a report would be an excellent way to avoid that "Duh! That whole subsystem was buried in a manual and I re-invented it because reading manuals from cover to cover sucks" feeling. The latter would be particularly nice for a less referene-oriented walk-through of a particular topic, perhaps written by someone with quite a bit of experience. I'm not so sure that a book about OTP would be that great a success---the OTP books are actually quite good, though they are much nicer to read on paper and, as far as I know, the only way to get paper copies is to buy a supported copy of Erlang. In any case, I mention all the books about Erlang in questions 3.5 and 3.6 of the all-new Erlang FAQ at http://www.ericsson.se/cslab/~mml/faq/x122.html#AEN160 A few of us had some corridor discussions about "a new Erlang book" a while back. Some thoughts which came out of that were: - Many people would like a more example-driven replacement for the "Erlang book". This would contain an up-to-date description of Erlang, contain different (and more) examples, choosing things which people are more likely to have come up against, e.g. a satellite control system seems pretty irrelevant, but a simple WWW server is something many of us have tried or at least thought about. It also seems tempting to move many of the longer the code examples out of the book and onto a www site. - Others would like an advanced Erlang book, maybe something like "Large Scale Erlang Software Design" (title rip-off deliberate). The catch here is that there are very few people qualified to write such a book, and most of them are busy working on big systems. - Writing an advanced book is likely to be strictly a labour of love, maybe 100 people would understand it. Of course, when Erlang really takes off... Is it possible to write a good book about OTP without it being an advanced Erlang book or being merely a rewrite of the OTP books? For instance, I can't see a huge scope for improving what the manuals say about Erlang applications and Supervision trees than the manuals have: http://www.erlang.org/documentation/doc/design_principles/part_frame.html Matthias From jhague@REDACTED Wed Mar 15 03:33:27 2000 From: jhague@REDACTED (James Hague) Date: Tue, 14 Mar 00 20:33:27 -0600 Subject: wonderings Message-ID: <200003150232.UAA04597@node-02.advancenet.net> >- Many people would like a more example-driven replacement for the > "Erlang book". This would contain an up-to-date description of > Erlang, contain different (and more) examples, choosing things > which people are more likely to have come up against, e.g. a > satellite control system seems pretty irrelevant, but a simple > WWW server is something many of us have tried or at least thought > about. I like the current Erlang book quite a bit. Part of the reason is that it's simply about the language itself, and doesn't muddle the waters with OTP issues. The existing book is well-written and a pleasant read. The only real omissions are the new features of Erlang, such as funs and list comprehensions. Rather than another book, I think it would informative to read some detailed tutorials on practical subjects, such as those you suggest. A WWW server would be interesting, as would be a simple mail reader. Something along the lines of a literate programming document might make a good format, with code and commentary interspersed. This works well for Erlang, because very little code is needed. James From vladdu@REDACTED Wed Mar 15 08:56:47 2000 From: vladdu@REDACTED (Vlad Dumitrescu) Date: Wed, 15 Mar 2000 08:56:47 CET Subject: wonderings Message-ID: <20000315075647.97381.qmail@hotmail.com> >I'd love to be able to buy a really neat, well-written book about more >advanced Erlang topics. I'd also love to get a monthly newsletter-style thing with nice Erlang ideas That was more or less what I had in mind too... Once the language is learned, one wants to see more ways to use it in day-by-day applications. >I'm not so sure that a book about OTP would be that great a success---the OTP books are actually quite good Yes, they are - as a reference. But for me reading reference documentation doesn't work half as good as reading/testing hands-on examples. There are also "hidden" problems and issues that only come up when working with an application - see Mnesia and JInterface for example. >e.g. a satellite control system seems pretty irrelevant, but a simple WWW >server is something many of us have tried or at least thought about. Some more examples could be: Luke's and Joe's Wikie implementations, Samuel's distributed power monitor, or even some of the "User Contributions" apps. In my opinion, a way to "convert" more people to Erlang would be to provide/describe/publish some general applications that people can easily relate to. A Web server is one of those apps -- what about writing an industrial strength one, and show it can easily compete with Apache and Xitami? Vlad ______________________________________________________ Get Your Private, Free Email at http://www.hotmail.com From mml+maillist@REDACTED Wed Mar 15 09:54:42 2000 From: mml+maillist@REDACTED (mml+maillist@REDACTED) Date: Wed, 15 Mar 2000 09:54:42 +0100 (MET) Subject: where to get the OTP books on paper In-Reply-To: <14542.35860.503099.145784@gargle.gargle.HOWL> References: <20000314084844.27662.qmail@hotmail.com> <14542.35860.503099.145784@gargle.gargle.HOWL> Message-ID: <14543.20434.310609.843430@gargle.gargle.HOWL> Following up my own post... me> the OTP books are actually quite good, though they are much me> nicer to read on paper and, as far as I know, the only way to me> get paper copies is to buy a supported copy of Erlang. It looks like you can also get the books by mailing Kristina at star@REDACTED The set consists of 11 books (most are quite thin, all together they take up about 15cm or 6in. on a shelf) and cost 1100 sek plus VAT plus shipping. That's roughly $140 US. Matthias From tonyp@REDACTED Wed Mar 15 10:53:36 2000 From: tonyp@REDACTED (Tony Pedley) Date: Wed, 15 Mar 2000 09:53:36 +0000 Subject: Arity of funs Message-ID: <38CF5D9F.9CB1072E@terminus.ericsson.se> Hi, Well I've searched the OTP book, trawled the erlang questions archive(very good by the way, however there should be an all button on the Available Subdirectories) and I still can't work out how to do it. How do you extract the arity of a Fun? e.g How do I do this F = fun(X,Y,Z) -> end, X = get_fun_arity(F). 3 All the best Tony -- ______________________________________________________________________ Tony Pedley mailto:tonyp@REDACTED Ericsson Intracom Ltd. Intranet : http://intracom.ericsson.se 1 Bede Island Internet : http://www.ericsson.co.uk/datacom/index.htm Leicester memoID : ECOM.CBERAM England Tel : +44 (0)116 2 542 400 LE2 7EU Fax : +44 (0)116 2 046 111 ______________________________________________________________________ -------------- next part -------------- An HTML attachment was scrubbed... URL: From bjorn@REDACTED Wed Mar 15 11:11:31 2000 From: bjorn@REDACTED (Bjorn Gustavsson) Date: 15 Mar 2000 11:11:31 +0100 Subject: Arity of funs In-Reply-To: Tony Pedley's message of Wed, 15 Mar 2000 09:53:36 +0000 References: <38CF5D9F.9CB1072E@terminus.ericsson.se> Message-ID: There is no way to find out the arity of a fun. There are, however, erlang:fun_info/1,2 BIFs that return some information about a fun, but not the arity. (These BIFs are meant to be used for debugging purposes, not for use in applications.) /Bjorn Tony Pedley writes: > > Content-type: text/plain ; charset = us-ascii > > Hi, > Well I've searched the OTP book, trawled the erlang questions archive(very good by the way, however > there should > be an all button on the Available Subdirectories) and I still can't work out how to do it. > > How do you extract the arity of a Fun? e.g How do I do this > > F = fun(X,Y,Z) -> end, > > X = get_fun_arity(F). > > 3 > > All the best > > Tony > > -- > ______________________________________________________________________ > Tony Pedley mailto:tonyp@REDACTED > Ericsson Intracom Ltd. Intranet : http://intracom.ericsson.se > 1 Bede Island Internet : http://www.ericsson.co.uk/datacom/index.htm > Leicester memoID : ECOM.CBERAM > England Tel : +44 (0)116 2 542 400 > LE2 7EU Fax : +44 (0)116 2 046 111 > ______________________________________________________________________ > > > -- Bj?rn Gustavsson Ericsson Utvecklings AB bjorn@REDACTED ?T2/UAB/F/P BOX 1505 +46 8 727 56 87 125 25 ?lvsj? From richardc@REDACTED Wed Mar 15 11:19:30 2000 From: richardc@REDACTED (Richard Carlsson) Date: Wed, 15 Mar 2000 11:19:30 +0100 (MET) Subject: Arity of funs In-Reply-To: <38CF5D9F.9CB1072E@terminus.ericsson.se> Message-ID: On Wed, 15 Mar 2000, Tony Pedley wrote: > Hi, > Well I've searched the OTP book, trawled the erlang questions > archive(very good by the way, however there should be an all button on > the Available Subdirectories) and I still can't work out how to do it. > > How do you extract the arity of a Fun? e.g How do I do this > > F = fun(X,Y,Z) -> end, > > X = get_fun_arity(F). > > 3 You don't, I'm sure. Sorry. 1: Neither the old representation of funs as tuples, nor the new representation in R6 contain the arity. (The BIF erlang:fun_info/1 can give you some information "for debugging purposes only", but not the arity.) 2. Even if you know the module where the source code resides, and the fun-table index of a particular fun, there is no way to ask the module what the arity of that fun is (short of disassembling the compiled code). Out of curiosity: why do you want to find the arity of an arbitrary fun? /Richard Carlsson Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://www.csd.uu.se/~richardc/ From tonyp@REDACTED Wed Mar 15 11:53:28 2000 From: tonyp@REDACTED (Tony Pedley) Date: Wed, 15 Mar 2000 10:53:28 +0000 Subject: Arity of funs References: Message-ID: <38CF6BA7.E7FDC309@terminus.ericsson.se> Hi We are using a block test server here which I am not sure is supported but is pretty simple. You define stubs of functions which are either not written yet or external to your block e.g bt:stub_fun_def(module,function,fun(A,B) -> ok end) These are stored on a ETS table and if during the running of the code a undef error is raised, the table is searched and the fun called instead. However it appears that the ETS table key is {module,function} so if we the same functions but with 2 arity values there is no way of indicating the difference in the table so the fun may fail because of incorrect number of parameters depending on which is stored. What we really require is the key to be {module,function,arity} and while that could be acheived by redfining the stub_fun_def function to be like bt:stub_fun_def(module,function,arity,fun(A,B) -> ok end) this would not be very backward compatible with everyones block tests, so what would be better is for the stub_fun_def function to be able to extract the funs arity when it is called and the the undef error handler would extract the required arity from the undef error message and call the correct fun. Anyway add a feature and people will use it! All the best Tony Richard Carlsson wrote: > On Wed, 15 Mar 2000, Tony Pedley wrote: > > > Hi, > > Well I've searched the OTP book, trawled the erlang questions > > archive(very good by the way, however there should be an all button on > > the Available Subdirectories) and I still can't work out how to do it. > > > > How do you extract the arity of a Fun? e.g How do I do this > > > > F = fun(X,Y,Z) -> end, > > > > X = get_fun_arity(F). > > > > 3 > > You don't, I'm sure. Sorry. > > 1: Neither the old representation of funs as tuples, nor the new > representation in R6 contain the arity. (The BIF erlang:fun_info/1 can > give you some information "for debugging purposes only", but not the > arity.) > > 2. Even if you know the module where the source code resides, and the > fun-table index of a particular fun, there is no way to ask the module > what the arity of that fun is (short of disassembling the compiled code). > > Out of curiosity: why do you want to find the arity of an arbitrary fun? > > /Richard Carlsson > > Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) > E-mail: Richard.Carlsson@REDACTED WWW: http://www.csd.uu.se/~richardc/ -- ______________________________________________________________________ Tony Pedley mailto:tonyp@REDACTED Ericsson Intracom Ltd. Intranet : http://intracom.ericsson.se 1 Bede Island Internet : http://www.ericsson.co.uk/datacom/index.htm Leicester memoID : ECOM.CBERAM England Tel : +44 (0)116 2 542 400 LE2 7EU Fax : +44 (0)116 2 046 111 ______________________________________________________________________ -------------- next part -------------- An HTML attachment was scrubbed... URL: From luke@REDACTED Wed Mar 15 11:36:07 2000 From: luke@REDACTED (Luke Gorrie) Date: 15 Mar 2000 11:36:07 +0100 Subject: Arity of funs In-Reply-To: Bjorn Gustavsson's message of "15 Mar 2000 11:11:31 +0100" References: <38CF5D9F.9CB1072E@terminus.ericsson.se> Message-ID: Bjorn Gustavsson writes: > There is no way to find out the arity of a fun. > > There are, however, erlang:fun_info/1,2 BIFs that return some information > about a fun, but not the arity. (These BIFs are meant to be used for > debugging purposes, not for use in applications.) Here's some horrible code for finding the arity of a fun. I don't know if it works on all versions of Erlang, depend what fun_info returns. I know it's ugly, but saying there is "no way" is provoking an ugly hack anyway :-) 21> ArgCounter = fun({env, [_, [{clause,_,Args,_,_}|_]|_]}) -> length(Args) end. #Fun 22> ArityFinder = fun(F) -> ArgCounter(erlang:fun_info(F, env)) end. #Fun 23> ArityFinder(ArityFinder). 1 24> ArityFinder(fun(X, 1, {2, Y}) -> true end). 3 From bjorn@REDACTED Wed Mar 15 11:49:48 2000 From: bjorn@REDACTED (Bjorn Gustavsson) Date: 15 Mar 2000 11:49:48 +0100 Subject: Arity of funs In-Reply-To: Luke Gorrie's message of 15 Mar 2000 11:36:07 +0100 References: <38CF5D9F.9CB1072E@terminus.ericsson.se> Message-ID: Your trick will only work on funs defined in the shell, not on funs defined in an arbitrary module. Furthermore, it is highly dependent on exactly how funs are represented internally in the shell. BTW, I deliberately decided to not implement a way to return the arity of a fun, because that information is stored in the fun table in the loaded code, not in the fun representation itself. And there might be a fun, but no loaded code for it. /Bjorn Luke Gorrie writes: > > Bjorn Gustavsson writes: > > > There is no way to find out the arity of a fun. > > > > There are, however, erlang:fun_info/1,2 BIFs that return some information > > about a fun, but not the arity. (These BIFs are meant to be used for > > debugging purposes, not for use in applications.) > > Here's some horrible code for finding the arity of a fun. I don't know > if it works on all versions of Erlang, depend what fun_info returns. I > know it's ugly, but saying there is "no way" is provoking an ugly hack > anyway :-) > > 21> ArgCounter = fun({env, [_, [{clause,_,Args,_,_}|_]|_]}) -> length(Args) end. > #Fun > 22> ArityFinder = fun(F) -> ArgCounter(erlang:fun_info(F, env)) end. > #Fun > 23> ArityFinder(ArityFinder). > 1 > 24> ArityFinder(fun(X, 1, {2, Y}) -> true end). > 3 > -- Bj?rn Gustavsson Ericsson Utvecklings AB bjorn@REDACTED ?T2/UAB/F/P BOX 1505 +46 8 727 56 87 125 25 ?lvsj? From matthias@REDACTED Wed Mar 15 11:59:00 2000 From: matthias@REDACTED (matthias@REDACTED) Date: Wed, 15 Mar 2000 11:59:00 +0100 (MET) Subject: Arity of funs In-Reply-To: References: <38CF5D9F.9CB1072E@terminus.ericsson.se> Message-ID: <14543.27892.196832.865367@gargle.gargle.HOWL> > There is no way to find out the arity of a fun. I've put a .beam file up at http://www.ericsson.se/cslab/~mml/besserwisser.beam Here's what it does: 4> besserwisser:arity(fun(_) -> a end). 1 5> besserwisser:arity(fun() -> a end). 0 6> besserwisser:arity(fun(p,q,r) -> a end). 3 How it works is a secret. Looking in the local filesystem is cheating, Bj?rn. Matthias From bjorn@REDACTED Wed Mar 15 12:13:05 2000 From: bjorn@REDACTED (Bjorn Gustavsson) Date: 15 Mar 2000 12:13:05 +0100 Subject: Arity of funs In-Reply-To: matthias@besserwisser.org's message of Wed, 15 Mar 2000 11:59:00 +0100 (MET) References: <38CF5D9F.9CB1072E@terminus.ericsson.se> <14543.27892.196832.865367@gargle.gargle.HOWL> Message-ID: OK, it is of course possible to find out the arity by applying the fun with different number of arguments and examine the EXIT code. There will be a badarity exception if the arity was wrong. This is still not a general solution, since the call may succeed and it may have unexpected side effects. This might or might not be a problem depending on what you are trying to achieve in the first place. What I've learned is that I should be more careful with my words. I should have written that there is no general, side-effect free way to obtain the arity of a fun. /Bjorn matthias@REDACTED writes: > > > > There is no way to find out the arity of a fun. > > I've put a .beam file up at > > http://www.ericsson.se/cslab/~mml/besserwisser.beam > > Here's what it does: > > 4> besserwisser:arity(fun(_) -> a end). > 1 > 5> besserwisser:arity(fun() -> a end). > 0 > 6> besserwisser:arity(fun(p,q,r) -> a end). > 3 > > How it works is a secret. Looking in the local filesystem is cheating, > Bj?rn. > > Matthias > -- Bj?rn Gustavsson Ericsson Utvecklings AB bjorn@REDACTED ?T2/UAB/F/P BOX 1505 +46 8 727 56 87 125 25 ?lvsj? From tony@REDACTED Wed Mar 15 13:01:24 2000 From: tony@REDACTED (Tony Rogvall) Date: Wed, 15 Mar 2000 13:01:24 +0100 Subject: Arity of funs References: <38CF5D9F.9CB1072E@terminus.ericsson.se> <14543.27892.196832.865367@gargle.gargle.HOWL> Message-ID: <38CF7B94.626D03EF@bluetail.com> matthias@REDACTED wrote: > > There is no way to find out the arity of a fun. > > I've put a .beam file up at > > http://www.ericsson.se/cslab/~mml/besserwisser.beam > > Here's what it does: > > 4> besserwisser:arity(fun(_) -> a end). > 1 > 5> besserwisser:arity(fun() -> a end). > 0 > 6> besserwisser:arity(fun(p,q,r) -> a end). > 3 > > How it works is a secret. Looking in the local filesystem is cheating, > Bj?rn. > > Matthias Try this: besserwisser:arity(fn:f(1)) and see how the besser works (read NOT) :-) also try besserwisser:arity(fn:f(5)) --------- -module(fn). -compile(export_all). f(0) -> fun() -> erlang:display(besserwisser) end; f(1) -> fun(A) -> erlang:display(besserwisser) end; f(2) -> fun(A,B) -> erlang:display(besserwisser) end; f(3) -> fun(A,B,C) -> erlang:display(besserwisser) end; f(4) -> fun(A,B,C,D) -> erlang:display(besserwisser) end; f(5) -> fun(x,x,x,x,x) -> erlang:display(besserwisser) end. -------- /Tony From kiciak_c@REDACTED Wed Mar 15 16:38:49 2000 From: kiciak_c@REDACTED (Kiciak Christophe) Date: Wed, 15 Mar 2000 15:38:49 +0000 Subject: Newbie node question Message-ID: <38CFAE89.B8A8EA2D@epita.fr> Hi ! First, sorry if it's a stupid question, I'm REALLY a beginner in Erlang... If I have 2 nodes A and B, and both "know" each other (B is in the nodes() of A and vice-versa). Is it possible for a node C no connect to A without having B in it's nodes() list ? I saw there is a disconnect_node function, but I can't find a connect_node one... Thanks a lot From Matthias.Lang@REDACTED Thu Mar 16 09:49:58 2000 From: Matthias.Lang@REDACTED (Matthias.Lang@REDACTED) Date: Thu, 16 Mar 2000 09:49:58 +0100 (MET) Subject: Arity of funs In-Reply-To: <38CF7B94.626D03EF@bluetail.com> References: <38CF5D9F.9CB1072E@terminus.ericsson.se> <14543.27892.196832.865367@gargle.gargle.HOWL> <38CF7B94.626D03EF@bluetail.com> Message-ID: <14544.41014.501587.883063@gargle.gargle.HOWL> Just to close off this topic... It caught my eye that the size of a fun depends on its 'complexity': 3> term_to_binary(fun() -> ok end). #Bin<158> 4> term_to_binary(fun(a,b,c,d) -> {p,q,r,s} end). #Bin<285> That led me to suspect the fun carries BEAM code around with it. To test that, I tried sending the fun around. For instance you can write the binary to disk, start a new node, load the binary, use binary_to_term and presto, you can execute the fun. Similarly you can send it to another node. Therefore it must be carrying the code around. Bj?rn cleared up a couple of things. Firstly, funs defined in the shell are special because they're not part of a module in the same way compiled fun code is. Only shell funs carry the code around. Secondly, the code being carried around isn't BEAM, it's a dump of the compiler's parse tree, a lot like Sun's implementation of C++ templates (do they still do it that way?). Matthias -------------------- P.S: here's the besserwisser code. It, of course, works just like Bj?rn and Tony guessed. -module(besserwisser). -export([arity/1]). arity(F) when function(F) -> loop(F, []). loop(F, Args) -> case catch (apply(F, Args)) of {'EXIT', {badarity, _}} -> loop(F, [0|Args]); _ -> length(Args) end. It only has side effects if the code you pass it has side effects, which I think is completely fair ;-) From Sean.Hinde@REDACTED Thu Mar 16 10:55:02 2000 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Thu, 16 Mar 2000 09:55:02 -0000 Subject: Newbie node question Message-ID: Kiciak, > First, sorry if it's a stupid question, I'm REALLY a beginner in > Erlang... We've all been there > If I have 2 nodes A and B, and both "know" each other (B is in the > nodes() of A and vice-versa). > Is it possible for a node C no connect to A without having B in it's > nodes() list ? > I saw there is a disconnect_node function, but I can't find a > connect_node one... Normally all nodes in an erlang system are fully meshed, so the act of connecting node C to either A or B will automatically connect them all together. The 'connect' command is net_adm:ping(nodea@REDACTED). Sean From etxuwig@REDACTED Thu Mar 16 11:12:55 2000 From: etxuwig@REDACTED (Ulf Wiger) Date: Thu, 16 Mar 2000 11:12:55 +0100 (MET) Subject: Newbie node question In-Reply-To: Message-ID: On Thu, 16 Mar 2000, Sean Hinde wrote: Sean>Kiciak, Sean> Sean>> First, sorry if it's a stupid question, I'm REALLY a beginner in Sean>> Erlang... Sean> Sean>We've all been there Sean> Sean>> If I have 2 nodes A and B, and both "know" each other (B is in the Sean>> nodes() of A and vice-versa). Sean>> Is it possible for a node C no connect to A without having B in it's Sean>> nodes() list ? Sean>> I saw there is a disconnect_node function, but I can't find a Sean>> connect_node one... Sean> Sean>Normally all nodes in an erlang system are fully meshed, so Sean>the act of connecting node C to either A or B will Sean>automatically connect them all together. Sean> Sean>The 'connect' command is net_adm:ping(nodea@REDACTED). But it is also possible to disable the "connect-all" semantics. Unfortunately, this has the side-effect that you cannot use global name registration. Quote from erl -man global: The server also performs the critical task of continuously monitoring changes in node configuration, if a node which runs a globally registered process goes down, the name will be globally unregistered. The server will also maintain a fully connected network. For example, if node N1 connects to node N2 (which is already connected to N3), the global server on N1 then N3 will make sure that also N1 and N3 are connected. If this is not desired, the command line flag -connect_all false must be passed to init at boot time. In this case, the name registration facility cannot be used (but the lock mechanism will still work.) So, to disable connect_all, try erl -connect_all false I recommend that you don't do this, though. It might have unexpected consequences. We at AXD 301 are trying to figure out ways to evolve from the connect_all philosophy without losing any central features of Erlang. I can't give you an ETOC on this. /Uffe -- Ulf Wiger, Chief Designer AXD 301 Ericsson Telecom AB tfn: +46 8 719 81 95 Varuv?gen 9, ?lvsj? mob: +46 70 519 81 95 S-126 25 Stockholm, Sweden fax: +46 8 719 43 44 From jbottoms@REDACTED Thu Mar 16 14:52:18 2000 From: jbottoms@REDACTED (John W. Bottoms) Date: Thu, 16 Mar 2000 08:52:18 -0500 Subject: Policy server Message-ID: <38D0E712.F92329A2@world.std.com> The New-New things... Is there any Erlang code available for a policy server? I'd be interested in that. We are trying to create a test environment to test an edge device. -John Bottoms FirstStar Data, Inc. Tel: (978) 369-4233 From etxuwig@REDACTED Mon Mar 20 14:54:04 2000 From: etxuwig@REDACTED (Ulf Wiger) Date: Mon, 20 Mar 2000 14:54:04 +0100 (MET) Subject: vendor support for Linux on laptops Message-ID: Perhaps this was only news to me, but here goes... I began shopping for a laptop last week, and thought that I'd pick one that could run Linux -- supported by the laptop vendor, that is, since I have better things to do at work. Going through Ericsson purchasing channels, I basically had to choose between Dell and HP (buying non-standard equipment is of course possible, but more work.) After a few days of searching, I found out that both HP and Dell will deliver their new laptops with Red Hat Linux, and will support it too! (: Of course, their web pages only mention M$, and their phone support will either tell you they don't have a clue, or even that you absolutely *cannot* run Linux on their laptops, but if you stay at it long enough, you'll eventually be able to locate someone who understands what you're talking about. This is progress (or... are we regressing?) (Sadly, Sun makes no mention of laptops on their HW compat. list for Solaris, and SUN Sweden had no info. If you want a supported UNIX on a PC laptop, Linux seems to be the one.) /Uffe -- Ulf Wiger, Chief Designer AXD 301 Ericsson Telecom AB tfn: +46 8 719 81 95 Varuv?gen 9, ?lvsj? mob: +46 70 519 81 95 S-126 25 Stockholm, Sweden fax: +46 8 719 43 44 From Sean.Hinde@REDACTED Mon Mar 20 17:11:22 2000 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Mon, 20 Mar 2000 16:11:22 -0000 Subject: vendor support for Linux on laptops Message-ID: > (Sadly, Sun makes no mention of laptops on their HW compat. list > for Solaris, and SUN Sweden had no info. If you want a supported > UNIX on a PC laptop, Linux seems to be the one.) I was looking at the same issue recently. There is a notebook computers list for Solaris 2.6 on the Sun site: http://soldc.sun.com/support/drivers/hcl/2.6/feb00/files/c0110.htm#X86HCL-9 Cheers, Sean From Olivier.Lefevre@REDACTED Mon Mar 20 18:37:29 2000 From: Olivier.Lefevre@REDACTED (Olivier.Lefevre@REDACTED) Date: Mon, 20 Mar 2000 12:37:29 -0500 Subject: vendor support for Linux on laptops In-Reply-To: Message-ID: For Solaris support on laptops, forget about SUN, which is now explicitely focusing on servers, and check out Xi Graphics (http://www.xig.com/) instead. -- O.L. This message contains confidential information and is intended only for the individual named. If you are not the named addressee you should not disseminate, distribute or copy this e-mail. Please notify the sender immediately by e-mail if you have received this e-mail by mistake and delete this e-mail from your system. E-mail transmission cannot be guaranteed to be secure or error-free as information could be intercepted, corrupted, lost, destroyed, arrive late or incomplete, or contain viruses. The sender therefore does not accept liability for any errors or omissions in the contents of this message which arise as a result of e-mail transmission. If verification is required please request a hard-copy version. This message is provided for informational purposes and should not be construed as a solicitation or offer to buy or sell any securities or related financial instruments. From raymond_archibald@REDACTED Mon Mar 20 19:47:53 2000 From: raymond_archibald@REDACTED (Raymond Archibald) Date: Mon, 20 Mar 2000 10:47:53 -0800 Subject: Erlang developers in North America? Message-ID: <00fa01bf929c$ccb79500$6700a8c0@righthinking.com> Hi, Does anybody know of any Erlang developers and/or users in North America (near San Francisco)? Regards Ray Archibald -------------- next part -------------- An HTML attachment was scrubbed... URL: From vances@REDACTED Mon Mar 20 20:03:17 2000 From: vances@REDACTED (Vance Shipley) Date: Mon, 20 Mar 2000 14:03:17 -0500 Subject: Erlang developers in North America? In-Reply-To: <00fa01bf929c$ccb79500$6700a8c0@righthinking.com> Message-ID: } Does anybody know of any Erlang developers and/or users in } North America (near San Francisco)? } } Regards } Ray Archibald We've been focusing on Erlang/OTP based development for the last couple years here at Motivity Telecom in Kitchener, Ontario, Canada. -Vance -------------- next part -------------- A non-text attachment was scrubbed... Name: Vance Shipley.vcf Type: text/x-vcard Size: 518 bytes Desc: not available URL: From feeley@REDACTED Tue Mar 21 02:34:14 2000 From: feeley@REDACTED (Marc Feeley) Date: Mon, 20 Mar 2000 20:34:14 -0500 Subject: Erlang developers in North America? In-Reply-To: <00fa01bf929c$ccb79500$6700a8c0@righthinking.com> (raymond_archibald@righthinking.com) References: <00fa01bf929c$ccb79500$6700a8c0@righthinking.com> Message-ID: <200003210134.UAA02395@trex.IRO.UMontreal.CA> > Hi, > Does anybody know of any Erlang developers and/or users in North America = > (near San Francisco)? > Regards > Ray Archibald At the University of Montreal we are working on the ETOS compiler for Erlang, which compiles Erlang to Scheme, and then to C using the Gambit-C compiler. I have a few graduate students, with very good training in Erlang, who will be finishing in the coming months. Montreal is rather far from SF, but who knows, maybe these students can be persuaded to move or to telecommute... Marc Feeley From Sean.Hinde@REDACTED Wed Mar 22 11:29:37 2000 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Wed, 22 Mar 2000 10:29:37 -0000 Subject: FW: Solaris on Laptops Message-ID: A guy I know in Sun provided this advice: Sean, I've got a Toshiba Satellite Pro480CDT. Running Solaris on Intel, especially Laptop is a tricky business, purely because of device supports. If you are buying a new laptop, check the list first and pick the one on it, don't just get any, as the chances of Solaris supporting new devices is slim. Solaris Developer Connection - Solaris (Intel Platform Edition) Driver News Alternative, run Linux. But this would depend on what you want to do. In terms of problem, we have very little, as the build is very consistant and well tested. I guess the only problem is battery, it doesn't last long as Solaris don't have a laptop power managment. Let me know if you want more info. Regards, Mike From Sean.Hinde@REDACTED Fri Mar 24 14:41:48 2000 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Fri, 24 Mar 2000 13:41:48 -0000 Subject: Changing Solaris environment variables so os:getenv/1 gets the ne w value Message-ID: Hi all, Something which has been perplexing me for a while. When running an embedded system, I want to be able to change the DISPLAY environment variable so that a call to to_erl can start appmon displayed on a remote host. If I simply do export DISPLAY=host:0.0 to_erl Attaching to /tmp/erlang.pipe.2 (^D to exit) (node@REDACTED)2> os:getenv("DISPLAY"). false I know I can set DISPLAY in the start script, but I don't want to have to restart the node to change the DISPLAY variable! Has anyone come up with a solution to this in the past? Thanks, Sean From etxuwig@REDACTED Fri Mar 24 15:59:51 2000 From: etxuwig@REDACTED (Ulf Wiger) Date: Fri, 24 Mar 2000 15:59:51 +0100 (MET) Subject: Changing Solaris environment variables so os:getenv/1 gets the ne w value In-Reply-To: Message-ID: Sean, Here's a little linked-in driver we use to change environment variables in a running system: This particular driver only cares about the TZ env var, and we use it to manage timezones in AXD301 (we let Solaris run in UTC time, and allow the operator to specify timezone/daylight savings parameters for Erlang). I'm sure you can modify it to set the DISPLAY variable instead. But if you only want to do it for appmon, you might want to consider running appmon on another node and connecting the nodes via distributed Erlang. Using the job control (Ctrl-G), you can also run a remote shell from this other node. The Erlang code associated with the driver looks like this: handle_call(initial_start, From, State) -> case code:priv_dir(sys1) of {error, _} -> % Will happen when running block test {reply, nok, []}; Path -> {Dir, _FileName} = sysI:find_file(filename:join(Path, "bin"), "sysTimezone.so"), erl_ddll:load_driver(Dir, "sysTimezone"), Port = open_port({spawn, sysTimezone}, [binary, {packet,2}]), [Obj] = mnesia:dirty_read({sys_timezone, ?SYS_TIMEZONE_INDEX}), send_to_driver(Port, Obj#sys_timezone.sysTZstring), {reply, ok, [Port]} end; handle_call({update, Tz}, From, [Port]) -> send_to_driver(Port, Tz), {reply, ok, [Port]}; send_to_driver(Port, Tz) -> Port ! {self(), {command, Tz}}. /Uffe On Fri, 24 Mar 2000, Sean Hinde wrote: SH>Hi all, SH> SH>Something which has been perplexing me for a while. SH> SH>When running an embedded system, I want to be able to change the DISPLAY SH>environment variable so that a call to to_erl can start appmon displayed on SH>a remote host. SH> SH>If I simply do SH>export DISPLAY=host:0.0 SH>to_erl SH>Attaching to /tmp/erlang.pipe.2 (^D to exit) SH> SH>(node@REDACTED)2> os:getenv("DISPLAY"). SH>false SH> SH> SH>I know I can set DISPLAY in the start script, but I don't want to have to SH>restart the node to change the DISPLAY variable! SH> SH>Has anyone come up with a solution to this in the past? SH> SH>Thanks, SH> SH>Sean SH> -- Ulf Wiger, Chief Designer AXD 301 Ericsson Telecom AB tfn: +46 8 719 81 95 Varuv?gen 9, ?lvsj? mob: +46 70 519 81 95 S-126 25 Stockholm, Sweden fax: +46 8 719 43 44 -------------- next part -------------- /* ----------------------------------------------------------------- * %CCaseFile: sysTimezone.c % * %CCaseRev: /main/Inc4/2 % * %CCaseDate: 97-11-26 % * %CCaseDocNo: 66/190 55-CNA 121 70 % * Author: Tomas Pihl * * Short description: * * This is a linked-in driver which sets the timezone for the * beam-process based on what an operator defines. * * ------------------------------------------------------------------ * Rev Date Name What * ----- ------- -------- -------------------------- * PA1 971125 etxtopi First try. * ------------------------------------------------------------------ */ #include #include #include #include "driver.h" static struct driver_entry my_driver_entry; static long sysTimezone_start(long, char*); static char* tz_string = 0; long sysTimezone_start(long port, char* buf) { #ifdef DEBUG fprintf(stderr, "sysTimezone.so loaded...\n"); #endif return (long) port; } int sysTimezone_stop() {} int sysTimezone_null_func() {} /* * output() - This is the main function. buf contains the TZ-string we * should use to set the timezone with. */ int sysTimezone_output(long port, char* buf, int count) { /* free tz_string if it has been malloced once already */ if (tz_string != 0) free(tz_string); tz_string = (char*) malloc(count+1); memcpy(tz_string, buf, count); tz_string[count] = '\0'; #ifdef DEBUG fprintf(stderr, "sysTimezone.so: Setting timezone to [%s]\n",tz_string); #endif /* eg. "TZ=AXD301-1AXD-2,116/2:00:00,265/2:00:00" */ putenv(tz_string); return 0; } /* * Initialize and return a driver entry struct */ struct driver_entry* driver_init(void *handle) { my_driver_entry.init = sysTimezone_null_func; /* Not used */ my_driver_entry.start = sysTimezone_start; my_driver_entry.stop = sysTimezone_stop; my_driver_entry.output = sysTimezone_output; my_driver_entry.ready_input = sysTimezone_null_func; my_driver_entry.ready_output = sysTimezone_null_func; my_driver_entry.driver_name = "sysTimezone"; my_driver_entry.finish = sysTimezone_null_func; my_driver_entry.handle = handle; /* MUST set this!!! */ return &my_driver_entry; } From Sean.Hinde@REDACTED Fri Mar 24 16:35:17 2000 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Fri, 24 Mar 2000 15:35:17 -0000 Subject: Changing Solaris environment variables so os:getenv/1 gets th e ne w value Message-ID: Uffe, Yet again thanks very much. You haven't thought about making the rest of AXD301 open source have you?!!! (Only joking I'm sure). > But if you only want to do it for appmon, you might want to > consider running appmon on another node and connecting the nodes via > distributed Erlang. Using the job control (Ctrl-G), you can also run a > remote shell from this other node. I am a bit concerned about the security of this mechanism. I'm not sure I want the COOKIE known so that people can back door in with their nice free downloaded erlang. It would also kick off a whole load of alarms when the new node went down. Hmmm food for thought though. Sean From etxuwig@REDACTED Fri Mar 24 17:30:01 2000 From: etxuwig@REDACTED (Ulf Wiger) Date: Fri, 24 Mar 2000 17:30:01 +0100 (MET) Subject: Changing Solaris environment variables so os:getenv/1 gets th e ne w value In-Reply-To: Message-ID: On Fri, 24 Mar 2000, Sean Hinde wrote: >Uffe, > >Yet again thanks very much. You haven't thought about making the rest of >AXD301 open source have you?!!! (Only joking I'm sure). Well, actually... I'd like to release much more, but we simply don't have the resources to spare for that kind of work (the pro-bono kind). We're quite busy expanding, as we've sold (according to press releases) over 130 switches to more than 15 countries within a short time (most during '99). As these are not exactly consumer-market products (list prices range from ca $500K, for a fully equipped 10GBps switch, to ... well, lots more for a 160GBps switch, I think this is a pretty good start. Since the AXD 301 contains more than half a million lines of Erlang code, this is also good news for Erlang. /Uffe -- Ulf Wiger, Chief Designer AXD 301 Ericsson Telecom AB tfn: +46 8 719 81 95 Varuv?gen 9, ?lvsj? mob: +46 70 519 81 95 S-126 25 Stockholm, Sweden fax: +46 8 719 43 44 From vances@REDACTED Fri Mar 24 19:47:12 2000 From: vances@REDACTED (Vance Shipley) Date: Fri, 24 Mar 2000 13:47:12 -0500 Subject: AXD301 Design In-Reply-To: Message-ID: Ulf, Is there a white paper which describes some of the architecture of this product as it pertains to Erlang? -Vance From peter@REDACTED Fri Mar 24 21:01:11 2000 From: peter@REDACTED (Peter H|gfeldt) Date: Fri, 24 Mar 2000 21:01:11 +0100 (MET) Subject: Changing Solaris environment variables so os:getenv/1 gets the ne w value In-Reply-To: Message-ID: Try os:putenv(Var, Value). /Peter ------------------------------------------------------------------------- Peter H?gfeldt e-mail : peter@REDACTED Open Telecom Platform On Fri, 24 Mar 2000, Sean Hinde wrote: > Hi all, > > Something which has been perplexing me for a while. > > When running an embedded system, I want to be able to change the DISPLAY > environment variable so that a call to to_erl can start appmon displayed on > a remote host. > > If I simply do > export DISPLAY=host:0.0 > to_erl > Attaching to /tmp/erlang.pipe.2 (^D to exit) > > (node@REDACTED)2> os:getenv("DISPLAY"). > false > > > I know I can set DISPLAY in the start script, but I don't want to have to > restart the node to change the DISPLAY variable! > > Has anyone come up with a solution to this in the past? > > Thanks, > > Sean > From vances@REDACTED Fri Mar 24 22:47:19 2000 From: vances@REDACTED (Vance Shipley) Date: Fri, 24 Mar 2000 16:47:19 -0500 Subject: release_handler not running Message-ID: I've just started using a R6B-0 port in my production embedded systems. In installing my application release I found a problem I had not encountered in previous versions: 1> release_handler:which_releases(). ** exited: {noproc,{gen_server,call,[release_handler,which_releases]}} ** It seems the release_handler process is not running. It is now necessary to do: 2> release_handler:start_link(). {ok,<0.30.0>} What has changed? -Vance From Sean.Hinde@REDACTED Fri Mar 24 23:01:14 2000 From: Sean.Hinde@REDACTED (Sean Hinde) Date: Fri, 24 Mar 2000 22:01:14 -0000 Subject: Changing Solaris environment variables so os:getenv/1 gets th e ne w value Message-ID: Thanks Peter: > Try os:putenv(Var, Value). > > /Peter An intriuging answer. There is no documentation on this, it is not in module os source, and m(os). returns: Exports: cmd/1 find_executable/1 find_executable/2 handle_call/3 handle_info/2 init/1 module_info/0 module_info/1 start_link/0 terminate/2 type/0 version/0 I guess it is a BIF. I must look through the source sometime and see what other goodies are in there. Cheers, Sean From gunilla@REDACTED Sun Mar 26 19:32:10 2000 From: gunilla@REDACTED (Gunilla Hugosson) Date: Sun, 26 Mar 2000 19:32:10 +0200 Subject: release_handler not running References: Message-ID: <38DE499A.D0EFDB29@erlang.ericsson.se> You have probably installed Erlang with the plain start script as default instead of the start_sasl script. The plain start script only starts the kernel and stdlib applications, and release_handler is part of the sasl application. Starting erlang as > erl -boot start_sasl should work. You can also re-install Erlang and select the start_sasl boot script as default. / Gunilla Vance Shipley wrote: > > I've just started using a R6B-0 port in my production > embedded systems. > > In installing my application release I found a problem I had > not encountered in previous versions: > > 1> release_handler:which_releases(). > ** exited: {noproc,{gen_server,call,[release_handler,which_releases]}} ** > > It seems the release_handler process is not running. It is now > necessary to do: > > 2> release_handler:start_link(). > {ok,<0.30.0>} > > What has changed? > > -Vance From etxmljg@REDACTED Mon Mar 27 11:27:36 2000 From: etxmljg@REDACTED (Ljung Magnus) Date: Mon, 27 Mar 2000 11:27:36 +0200 Subject: Tcl/Tk Message-ID: <38DF2988.B9FBBCF2@kk.etx.ericsson.se> Hi! I want to add an Erlang programming language interface to a Tcl/Tk application. I'm using the erl_interface to C with the libraries libei.a and liberl_interface.a. Compiling and inking a stand-alone application C-Erlang works. When compiling a loadable package to Tcl/Tk adding a Tcl command using one of the Erlang C library function something goes wrong. Loading the shared library in tclsh I get the error: relocation error: file /home/etxmljg/application/app.o: symbol erl_init_nothreads: referenced symbol not found I guess this means that the runtime linker cant find the function in the Erlang library. The result is the same for PTHREADS and STHREADS as well. Is there any environment variable that I have missed or does it depend on how the Erlang libraries have been compiled? Compiler flags used: gcc -O2 -shared -fPIC -R/EDUP/Otp/0/lib/erl_interface-3.2/lib -I/EDUP/Tcl/0/include/ -L/EDUP/Tcl/0/lib -I/EDUP/Otp/0/lib/erl_interface-3.2/include -L/EDUP/Otp/0/lib/erl_interface-3.2/lib \ -lerl_interface -lei -lm -ltcl app.c -o app.so Regards // Magnus From info@REDACTED Mon Mar 27 13:57:06 2000 From: info@REDACTED (Holiday Zone) Date: Mon, 27 Mar 2000 12:57:06 +0100 (BST) Subject: holiday accommodation Message-ID: <200003271157.MAB29525@shaggy.lineone.net> I am writing with regard to your holiday accommodation. [If you have been sent this mail by mistake please ignore - you will be sent no more mails] I am sure you have heard of people advertising their holiday accommodation on the Internet - you may even be doing so already. Whether you have your own website, advertise on the Internet now or have considered it I would like to introduce Holiday Zone - the Internets best online advertising board for holiday accommodation world-wide. You can advertise your holiday accommodation with Holiday Zone for JUST 29.99 GB Pounds FOR A ONE YEAR ADVERT!! See below for currency conversions. Visit http://www.holidayzone.co.uk and place your advert now!! WHAT CAN HOLIDAY ZONE OFFER YOU? * Professionally designed, easy-to-use website. * A variety of ways to place your advert - online, via e-mail or we offer a full postal service for non-internet users. * Online credit card payment option. * Personal service and support from the Holiday Zone team. * A webaddress of your own or direct links to your existing website. * Direct e-mail links (i.e. people will be able to e-mail you directly from your advert) * A one year advert for just 29.99 GBP - no extra hidden costs!! ADVERTISING HOLIDAY ACCOMMODATION ON THE INTERNET: Advertising with Holiday Zone ensures that your holiday accommodation is seen by more people worldwide. Holiday Zone is registered with over 500 web based search engines and is advertised in magazines, on the Internet, and in papers. Because of our extensive advertising campaign Holiday Zone has over 20,000 hits a month from people searching for all types of holiday accommodation in a wide variety of destinations worldwide. You benefit from Holiday Zone's extensive advertising campaign because everytime we draw people to Holiday Zone they are potential customers for your holiday accommodation. The Internet is the world's fastest growing media. Today there are 275 million people world-wide who have access to the Internet. On-line advertising is rapidly becoming the most effective way to target potential customers seeking holiday accommodation. Visit http://www.holidayzone.co.uk and place your advert now! If you have any questions about Holiday Zone please contact us. We look forward to hearing from you. Anne Smith Holiday Zone mailto:anne@REDACTED http://www.holidayzone.co.uk +44 (0)181 5587595 CURRENCY CONVERSION (on 17th Feb 00) * 48 USD * 69 CAD * 76 AUD * 77 NZD * 8,118 ESP * 320 FRF * 94 ITL For other currencies please click here: http://www.xe.net/ucc/ ***** This email is a one off - you will be sent no more emails by Holiday Zone ****** From etxuwig@REDACTED Mon Mar 27 18:35:10 2000 From: etxuwig@REDACTED (Ulf Wiger) Date: Mon, 27 Mar 2000 18:35:10 +0200 (MET DST) Subject: AXD301 Design In-Reply-To: Message-ID: On Fri, 24 Mar 2000, Vance Shipley wrote: vance>Ulf, vance> vance>Is there a white paper which describes some of the architecture vance>of this product as it pertains to Erlang? vance> vance> -Vance The closest thing I've found is: http://www.ericsson.com/datacom/emedia/ericssonvol31iss6.pdf For those of you who don't feel that the URL is intuitive enough, here's the title of the document: "AXD 301: A new generation ATM switching system" Staffan Blau, Jan Rooth, Jorgen Axell, Fiffi Hellstrand, Magnus Buhrgard, Tommy Westin, Goran Wicklund (Computer Networks 31 1999 559-582) /Uffe -- Ulf Wiger, Chief Designer AXD 301 Ericsson Telecom AB tfn: +46 8 719 81 95 Varuv?gen 9, ?lvsj? mob: +46 70 519 81 95 S-126 25 Stockholm, Sweden fax: +46 8 719 43 44 From per@REDACTED Mon Mar 27 18:40:07 2000 From: per@REDACTED (Per Hedeland) Date: Mon, 27 Mar 2000 18:40:07 +0200 (MET DST) Subject: Tcl/Tk In-Reply-To: <38DF2988.B9FBBCF2@kk.etx.ericsson.se> References: <38DF2988.B9FBBCF2@kk.etx.ericsson.se> Message-ID: <200003271640.SAA02849@aalborg.du.uab.ericsson.se> Ljung Magnus wrote: >I want to add an Erlang programming language interface to a Tcl/Tk >application. I'm using the erl_interface to C with the libraries libei.a >and liberl_interface.a. Compiling and inking a stand-alone application >C-Erlang works. When compiling a loadable package to Tcl/Tk adding a Tcl >command using one of the Erlang C library function something goes wrong. >Loading the shared library in tclsh I get the error: relocation error: >file /home/etxmljg/application/app.o: symbol erl_init_nothreads: >referenced symbol not found > >I guess this means that the runtime linker cant find the function in the >Erlang library. The result is the same for PTHREADS and STHREADS as >well. Is there any environment variable that I have missed or does it >depend on how the Erlang libraries have been compiled? > >Compiler flags used: >gcc -O2 -shared -fPIC -R/EDUP/Otp/0/lib/erl_interface-3.2/lib >-I/EDUP/Tcl/0/include/ -L/EDUP/Tcl/0/lib >-I/EDUP/Otp/0/lib/erl_interface-3.2/include >-L/EDUP/Otp/0/lib/erl_interface-3.2/lib \ > -lerl_interface -lei -lm -ltcl app.c -o app.so Hm, you're doing some pretty complex stuff here, and I'm not sure your problems have much if anything to do with Erlang... - however the solution seems simple: Move the 'app.c' earlier in the commandline, such that it is before at least the '-L/.../erl_interface-3.2/lib -lerl_interface -lei' part - the linker needs to have processed the object produced from your app.c before it searches liberl_interface, in order to know that it should pull in from the library the object that satisfies the erl_init_nothreads reference (repeat for lots of other references in this case, but dlopen() only reports the first failure). That's why you generally have the library specifications towards the end of a linker commandline... - and if you weren't building a "shared object", you would have gotten the error at link time instead (presumably your successful build used a very different commandline), but since the reference may be satisfied at runtime in a way that the linker knows nothing about (e.g. through being defined in the binary that loads the object), it can't flag this as an error. Another solution (with different properties) would presumably be to build shared versions of libei and liberl_interface - this is left as an exercise for the reader...:-) --Per Hedeland per@REDACTED PS If the -R option above means what I think it does (it's not in my gcc man page:-), i.e. runtime library search path, it's a no-op unless you have put some shared libraries of your own in that directory. From per.bohlin@REDACTED Tue Mar 28 08:24:30 2000 From: per.bohlin@REDACTED (Per Bohlin) Date: Tue, 28 Mar 2000 08:24:30 +0200 Subject: Tcl/Tk References: <38DF2988.B9FBBCF2@kk.etx.ericsson.se> Message-ID: <38E0501E.13E2C8D7@erv.ericsson.se> Hi Magnus! I like the idea of what you are trying to do. It has some resemblance to what I have done in GTE. The tool used to make the Motif user interfaces for some element management systems at Ericsson. My theory about your problem is simply as follows. erl_interface and ei are only there for static linking. When you make a shared library, which you do, no linking is done. The -l flags you give only puts information in the library that those libraries in theire turn should be loaded when your library is loaded. Thus you get no error when compiling. When running there is no erl_interface and ei to load so the first function in there that gets called fails. That first function would be erl_init which is a macro defined to call erl_init_nothreads in your case. But this is just a theory. I only have experience of using the SUN Workshop compilers to make shared libraries. I think that would complain in the compilation phase. If you have the source code you should be able to make shared library versions of erl_interface and ei. Regards Per Bohlin Ljung Magnus wrote: > > Hi! > > I want to add an Erlang programming language interface to a Tcl/Tk > application. I'm using the erl_interface to C with the libraries libei.a > and liberl_interface.a. Compiling and inking a stand-alone application > C-Erlang works. When compiling a loadable package to Tcl/Tk adding a Tcl > command using one of the Erlang C library function something goes wrong. > Loading the shared library in tclsh I get the error: relocation error: > file /home/etxmljg/application/app.o: symbol erl_init_nothreads: > referenced symbol not found > > I guess this means that the runtime linker cant find the function in the > Erlang library. The result is the same for PTHREADS and STHREADS as > well. Is there any environment variable that I have missed or does it > depend on how the Erlang libraries have been compiled? > > Compiler flags used: > gcc -O2 -shared -fPIC -R/EDUP/Otp/0/lib/erl_interface-3.2/lib > -I/EDUP/Tcl/0/include/ -L/EDUP/Tcl/0/lib > -I/EDUP/Otp/0/lib/erl_interface-3.2/include > -L/EDUP/Otp/0/lib/erl_interface-3.2/lib \ > -lerl_interface -lei -lm -ltcl app.c -o app.so > > Regards // Magnus From etxmljg@REDACTED Tue Mar 28 08:39:24 2000 From: etxmljg@REDACTED (Ljung Magnus) Date: Tue, 28 Mar 2000 08:39:24 +0200 (MET DST) Subject: Tcl/Tk Message-ID: <200003280639.IAA24625@kkb3> Hi Per & Per! Like always when calling out for help you find part of the solution at the same instance. A simple way to get access to the Erlang libraries is to re-compile Tcl with a function call to them included in the sourcecode. This is not the best solution but gives me the possibility to proceed until I find something better. I believe the theory of static linking is right on the money. I found a reference to a simular problem using shared libraries in Tcl. Your suggestion to recompile the Erlang libraries to shared ones sounds like the way forward to make the solution more seamless. Thanks // Magnus > Subject: Re: Tcl/Tk > To: Ljung Magnus > Cc: erlang-questions@REDACTED > MIME-version: 1.0 > Content-transfer-encoding: 7bit > X-Accept-Language: en > > Hi Magnus! > > I like the idea of what you are trying to do. It has some resemblance to > what > I have done in GTE. The tool used to make the Motif user interfaces for > some element management systems at Ericsson. > > My theory about your problem is simply as follows. > > erl_interface and ei are only there for static linking. > When you make a shared library, which you do, no linking is done. > The -l flags you give only puts information in the library that > those libraries in theire turn should be loaded when your library is > loaded. > Thus you get no error when compiling. > > When running there is no erl_interface and ei to load so the first > function > in there that gets called fails. That first function would be erl_init > which is a macro defined to call erl_init_nothreads in your case. > > But this is just a theory. I only have experience of using the SUN > Workshop > compilers to make shared libraries. I think that would complain in the > compilation phase. > > If you have the source code you should be able to make shared library > versions > of erl_interface and ei. > > Regards > > Per Bohlin > > > Hm, you're doing some pretty complex stuff here, and I'm not sure your > problems have much if anything to do with Erlang... - however the > solution seems simple: Move the 'app.c' earlier in the commandline, such > that it is before at least the '-L/.../erl_interface-3.2/lib > -lerl_interface -lei' part - the linker needs to have processed the > object produced from your app.c before it searches liberl_interface, in > order to know that it should pull in from the library the object that > satisfies the erl_init_nothreads reference (repeat for lots of other > references in this case, but dlopen() only reports the first failure). > > That's why you generally have the library specifications towards the end > of a linker commandline... - and if you weren't building a "shared > object", you would have gotten the error at link time instead > (presumably your successful build used a very different commandline), > but since the reference may be satisfied at runtime in a way that the > linker knows nothing about (e.g. through being defined in the binary > that loads the object), it can't flag this as an error. > > Another solution (with different properties) would presumably be to > build shared versions of libei and liberl_interface - this is left as an > exercise for the reader...:-) > > --Per Hedeland > per@REDACTED > > PS If the -R option above means what I think it does (it's not in my gcc > man page:-), i.e. runtime library search path, it's a no-op unless you > have put some shared libraries of your own in that directory. > > > > Ljung Magnus wrote: > > > > Hi! > > > > I want to add an Erlang programming language interface to a Tcl/Tk > > application. I'm using the erl_interface to C with the libraries libei.a > > and liberl_interface.a. Compiling and inking a stand-alone application > > C-Erlang works. When compiling a loadable package to Tcl/Tk adding a Tcl > > command using one of the Erlang C library function something goes wrong. > > Loading the shared library in tclsh I get the error: relocation error: > > file /home/etxmljg/application/app.o: symbol erl_init_nothreads: > > referenced symbol not found > > > > I guess this means that the runtime linker cant find the function in the > > Erlang library. The result is the same for PTHREADS and STHREADS as > > well. Is there any environment variable that I have missed or does it > > depend on how the Erlang libraries have been compiled? > > > > Compiler flags used: > > gcc -O2 -shared -fPIC -R/EDUP/Otp/0/lib/erl_interface-3.2/lib > > -I/EDUP/Tcl/0/include/ -L/EDUP/Tcl/0/lib > > -I/EDUP/Otp/0/lib/erl_interface-3.2/include > > -L/EDUP/Otp/0/lib/erl_interface-3.2/lib \ > > -lerl_interface -lei -lm -ltcl app.c -o app.so > > > > Regards // Magnus From not.for.email@REDACTED Tue Mar 28 09:00:18 2000 From: not.for.email@REDACTED (Gordon Beaton) Date: 28 Mar 2000 07:00:18 GMT Subject: Tcl/Tk References: <200003280639.IAA24625@kkb3> Message-ID: <8bpla2$hdq$1@news.du.uab.ericsson.se> On 28 Mar 2000 06:39:24 GMT, Ljung Magnus wrote: > I believe the theory of static linking is right on the money. I > found a reference to a simular problem using shared libraries in > Tcl. > > Your suggestion to recompile the Erlang libraries to shared ones > sounds like the way forward to make the solution more seamless. The Erlang libraries are already compiled using -fPIC so no recompilation should be necessary. You can extract the object files and make a shared library from them directly if that is what you want to do. However I think the original problem can be solved using Per Hedeland's suggestion earlier in this thread. What does 'nm app.so' report? /gordon -- g o r d o n . b e a t o n @ e r i c s s o n . c o m From per.bohlin@REDACTED Tue Mar 28 10:04:05 2000 From: per.bohlin@REDACTED (Per Bohlin) Date: Tue, 28 Mar 2000 10:04:05 +0200 Subject: Tcl/Tk References: <200003280639.IAA24625@kkb3> <8bpla2$hdq$1@news.du.uab.ericsson.se> Message-ID: <38E06775.307340B2@erv.ericsson.se> Gordon Beaton wrote: > > On 28 Mar 2000 06:39:24 GMT, Ljung Magnus wrote: > > I believe the theory of static linking is right on the money. I > > found a reference to a simular problem using shared libraries in > > Tcl. > > > > Your suggestion to recompile the Erlang libraries to shared ones > > sounds like the way forward to make the solution more seamless. > > The Erlang libraries are already compiled using -fPIC so no > recompilation should be necessary. You can extract the object files > and make a shared library from them directly if that is what you want > to do. I did not know that. Sorry. I thought that linking with -l when making a shared library only meant to put information to the run-time linker about further run-time linking. I had never thought about linking in position independent code from a static archive. If that is possible, I agree; the order of the things when compiling and linking is very important. > > However I think the original problem can be solved using Per > Hedeland's suggestion earlier in this thread. What does 'nm app.so' > report? And what does ldd app.so say? > > /gordon > > -- > g o r d o n . b e a t o n @ e r i c s s o n . c o m /Per Bohlin From per@REDACTED Tue Mar 28 10:06:18 2000 From: per@REDACTED (Per Hedeland) Date: Tue, 28 Mar 2000 10:06:18 +0200 (MET DST) Subject: Tcl/Tk In-Reply-To: <200003280639.IAA24625@kkb3> References: <200003280639.IAA24625@kkb3> Message-ID: <200003280806.e2S86Iw26851@super.du.uab.ericsson.se> Ljung Magnus wrote: >Like always when calling out for help you find part of the solution at the same >instance. A simple way to get access to the Erlang libraries is to re-compile >Tcl with a function call to them included in the sourcecode. That may work in this case, but not in general I think. Only objects (i.e. .o files) in an archive that satisfy unresolved references will be included with the binary, thus objects that are only called from your loadable object will still be missing at runtime. If it works, it's because the function you call directly from tcl in turn, directly or indirectly, calls enough other functions to pull in all the needed objects. Plus of course it will make the erl_interface libraries "bundled" with tcl rather than with your shared object, which is probably not what you wanted. > This is not the >best solution but gives me the possibility to proceed until I find something >better. Did you even try the trivial one I suggested? Here's a simplified demonstration to show that it works (and that Per B is partially wrong:-) - run on Solaris 2.6 (I assume Solaris from your -R, you didn't say what OS it was): % cat app.c foo(){erl_init_nothreads();} % gcc -O2 -shared -fPIC -L/usr/local/lib/erlang/lib/erl_interface-3.2/lib -lerl_interface app.c -o app.so % ls -l app.so -rwxr-xr-x 1 per 23836 Mar 28 09:51 app.so % nm app.so | grep erl_init_nothreads [82] | 0| 0|NOTY |GLOB |0 |UNDEF |erl_init_nothreads % gcc -O2 -shared -fPIC app.c -L/usr/local/lib/erlang/lib/erl_interface-3.2/lib -lerl_interface -o app.so % ls -l app.so -rwxr-xr-x 1 per 124804 Mar 28 09:52 app.so % nm app.so | grep erl_init_nothreads [187] | 7832| 24|FUNC |GLOB |0 |10 |erl_init_nothreads >Your suggestion to recompile the Erlang libraries to shared ones sounds like the >way forward to make the solution more seamless. As I wrote, it has different properties: The shared object will be smaller, but the erl_interface libraries have to be around - and findable by the runtime linker - at runtime. The tradeoff isn't clear-cut, it depends e.g. on what you intend to do with the shared object distribution-wise. --Per Hedeland per@REDACTED From etxmljg@REDACTED Tue Mar 28 10:58:33 2000 From: etxmljg@REDACTED (Ljung Magnus) Date: Tue, 28 Mar 2000 10:58:33 +0200 (MET DST) Subject: Tcl/Tk Message-ID: <200003280858.KAA29112@kkb3> Hi Per, I tried the simple fix but could not get it to work. Get problems with the Tcl library: gcc -O2 -shared -fPIC app.c -I/EDUP/Tcl/0/include/ -I/EDUP/Otp/0/lib/erl_interface-3.2/include -L/EDUP/Tcl/0/lib -L/EDUP/Otp/0/lib/erl_interface-3.2/lib \ -lerl_interface -lei -lm -ltcl -o app.so /EDUP/Tcl/0/lib/libtcl.a(tclAsync.o) 0x180 /EDUP/Tcl/0/lib/libtcl.a(tclAsync.o) 0x20 /EDUP/Tcl/0/lib/libtcl.a(tclAsync.o) ld: fatal: relocations remain against allocatable but non-writable sections You're probably correct that only my function call added in the Tcl source code will work but not the rest of the library functions...too bad. Solaris 2.6 is the OS used and any help on how to make the Erlang libraries shared assuming available object code? The application is for a Tcl/Tk program handling automatic tests of a Erlang node. This application adds a device package for the Network Elements so a configuration of the installation site is simpler than requiring a specific version of Tcl. Getting shared Erlang libraries would thus be better if there are no other solution. //Magnus P.S I do not subsrcibe to the mailing list yet so please send CC with the answer to me. > To: etxmljg@REDACTED > Subject: Re: Tcl/Tk > Cc: erlang-questions@REDACTED > Mime-Version: 1.0 > > Ljung Magnus wrote: > >Like always when calling out for help you find part of the solution at the same > >instance. A simple way to get access to the Erlang libraries is to re-compile > >Tcl with a function call to them included in the sourcecode. > > That may work in this case, but not in general I think. Only objects > (i.e. .o files) in an archive that satisfy unresolved references will be > included with the binary, thus objects that are only called from your > loadable object will still be missing at runtime. If it works, it's > because the function you call directly from tcl in turn, directly or > indirectly, calls enough other functions to pull in all the needed > objects. Plus of course it will make the erl_interface libraries > "bundled" with tcl rather than with your shared object, which is > probably not what you wanted. > > > This is not the > >best solution but gives me the possibility to proceed until I find something > >better. > > Did you even try the trivial one I suggested? Here's a simplified > demonstration to show that it works (and that Per B is partially > wrong:-) - run on Solaris 2.6 (I assume Solaris from your -R, you didn't > say what OS it was): > > % cat app.c > foo(){erl_init_nothreads();} > % gcc -O2 -shared -fPIC -L/usr/local/lib/erlang/lib/erl_interface-3.2/lib -lerl_interface app.c -o app.so > % ls -l app.so > -rwxr-xr-x 1 per 23836 Mar 28 09:51 app.so > % nm app.so | grep erl_init_nothreads > [82] | 0| 0|NOTY |GLOB |0 |UNDEF |erl_init_nothreads > % gcc -O2 -shared -fPIC app.c -L/usr/local/lib/erlang/lib/erl_interface-3.2/lib -lerl_interface -o app.so > % ls -l app.so > -rwxr-xr-x 1 per 124804 Mar 28 09:52 app.so > % nm app.so | grep erl_init_nothreads [187] | 7832| 24|FUNC |GLOB |0 |10 |erl_init_nothreads > > > >Your suggestion to recompile the Erlang libraries to shared ones sounds like the > >way forward to make the solution more seamless. > > As I wrote, it has different properties: The shared object will be > smaller, but the erl_interface libraries have to be around - and > findable by the runtime linker - at runtime. The tradeoff isn't > clear-cut, it depends e.g. on what you intend to do with the shared > object distribution-wise. > > --Per Hedeland > per@REDACTED From per.bohlin@REDACTED Tue Mar 28 12:21:25 2000 From: per.bohlin@REDACTED (Per Bohlin) Date: Tue, 28 Mar 2000 12:21:25 +0200 Subject: Tcl/Tk References: <200003280858.KAA29112@kkb3> Message-ID: <38E087A5.4A2E34E8@erv.ericsson.se> Hi again Magnus. I don't know if I dare to put in an other theory here but... Could it be that the tcl library is not compiled to have position independent code? Since you should alreaddy have everything in there when runing tcl you could try to just remove -ltcl from your compilation command. /Per Bohlin Ljung Magnus wrote: > > Hi Per, > > I tried the simple fix but could not get it to work. > Get problems with the Tcl library: > gcc -O2 -shared -fPIC app.c -I/EDUP/Tcl/0/include/ > -I/EDUP/Otp/0/lib/erl_interface-3.2/include -L/EDUP/Tcl/0/lib > -L/EDUP/Otp/0/lib/erl_interface-3.2/lib \ > -lerl_interface -lei -lm -ltcl -o app.so > /EDUP/Tcl/0/lib/libtcl.a(tclAsync.o) > 0x180 > /EDUP/Tcl/0/lib/libtcl.a(tclAsync.o) > 0x20 > /EDUP/Tcl/0/lib/libtcl.a(tclAsync.o) > ld: fatal: relocations remain against allocatable but non-writable sections > > You're probably correct that only my function call added in the Tcl source code > will work but not the rest of the library functions...too bad. > Solaris 2.6 is the OS used and any help on how to make the Erlang libraries > shared assuming available object code? > > The application is for a Tcl/Tk program handling automatic tests of a Erlang > node. This application adds a device package for the Network Elements so a > configuration of the installation site is simpler than requiring a specific > version of Tcl. Getting shared Erlang libraries would thus be better if there > are no other solution. > > //Magnus > > P.S I do not subsrcibe to the mailing list yet so please send CC with the answer > to me. > > > To: etxmljg@REDACTED > > Subject: Re: Tcl/Tk > > Cc: erlang-questions@REDACTED > > Mime-Version: 1.0 > > > > Ljung Magnus wrote: > > >Like always when calling out for help you find part of the solution at the > same > > >instance. A simple way to get access to the Erlang libraries is to re-compile > > >Tcl with a function call to them included in the sourcecode. > > > > That may work in this case, but not in general I think. Only objects > > (i.e. .o files) in an archive that satisfy unresolved references will be > > included with the binary, thus objects that are only called from your > > loadable object will still be missing at runtime. If it works, it's > > because the function you call directly from tcl in turn, directly or > > indirectly, calls enough other functions to pull in all the needed > > objects. Plus of course it will make the erl_interface libraries > > "bundled" with tcl rather than with your shared object, which is > > probably not what you wanted. > > > > > This is not the > > >best solution but gives me the possibility to proceed until I find something > > >better. > > > > Did you even try the trivial one I suggested? Here's a simplified > > demonstration to show that it works (and that Per B is partially > > wrong:-) - run on Solaris 2.6 (I assume Solaris from your -R, you didn't > > say what OS it was): > > > > % cat app.c > > foo(){erl_init_nothreads();} > > % gcc -O2 -shared -fPIC -L/usr/local/lib/erlang/lib/erl_interface-3.2/lib > -lerl_interface app.c -o app.so > > % ls -l app.so > > -rwxr-xr-x 1 per 23836 Mar 28 09:51 app.so > > % nm app.so | grep erl_init_nothreads > > [82] | 0| 0|NOTY |GLOB |0 |UNDEF |erl_init_nothreads > > % gcc -O2 -shared -fPIC app.c > -L/usr/local/lib/erlang/lib/erl_interface-3.2/lib -lerl_interface -o app.so > > % ls -l app.so > > -rwxr-xr-x 1 per 124804 Mar 28 09:52 app.so > > % nm app.so | grep erl_init_nothreads [187] > | 7832| 24|FUNC |GLOB |0 |10 |erl_init_nothreads > > > > > > >Your suggestion to recompile the Erlang libraries to shared ones sounds like > the > > >way forward to make the solution more seamless. > > > > As I wrote, it has different properties: The shared object will be > > smaller, but the erl_interface libraries have to be around - and > > findable by the runtime linker - at runtime. The tradeoff isn't > > clear-cut, it depends e.g. on what you intend to do with the shared > > object distribution-wise. > > > > --Per Hedeland > > per@REDACTED From etxmljg@REDACTED Tue Mar 28 12:42:32 2000 From: etxmljg@REDACTED (Ljung Magnus) Date: Tue, 28 Mar 2000 12:42:32 +0200 (MET DST) Subject: Tcl/Tk-works Message-ID: <200003281042.MAA01906@kkb3> Hi Per! It works with the last tip from you. Thank You all for the help. //Magnus > Subject: Re: Tcl/Tk > To: Ljung Magnus > Cc: per@REDACTED, erlang-questions@REDACTED, gordon.beaton@REDACTED, per.bohlin@REDACTED > MIME-version: 1.0 > Content-transfer-encoding: 7bit > X-Accept-Language: en > > Hi again Magnus. > > I don't know if I dare to put in an other theory here > but... > > Could it be that the tcl library is not compiled to have position > independent code? > Since you should alreaddy have everything in there when runing tcl > you could try to just remove -ltcl from your compilation command. > > /Per Bohlin > > Ljung Magnus wrote: > > > > Hi Per, > > > > I tried the simple fix but could not get it to work. > > Get problems with the Tcl library: > > gcc -O2 -shared -fPIC app.c -I/EDUP/Tcl/0/include/ > > -I/EDUP/Otp/0/lib/erl_interface-3.2/include -L/EDUP/Tcl/0/lib > > -L/EDUP/Otp/0/lib/erl_interface-3.2/lib \ > > -lerl_interface -lei -lm -ltcl -o app.so > > /EDUP/Tcl/0/lib/libtcl.a(tclAsync.o) > > 0x180 > > /EDUP/Tcl/0/lib/libtcl.a(tclAsync.o) > > 0x20 > > /EDUP/Tcl/0/lib/libtcl.a(tclAsync.o) > > ld: fatal: relocations remain against allocatable but non-writable sections > > > > You're probably correct that only my function call added in the Tcl source code > > will work but not the rest of the library functions...too bad. > > Solaris 2.6 is the OS used and any help on how to make the Erlang libraries > > shared assuming available object code? > > > > The application is for a Tcl/Tk program handling automatic tests of a Erlang > > node. This application adds a device package for the Network Elements so a > > configuration of the installation site is simpler than requiring a specific > > version of Tcl. Getting shared Erlang libraries would thus be better if there > > are no other solution. > > > > //Magnus > > > > P.S I do not subsrcibe to the mailing list yet so please send CC with the answer > > to me. > > > > > To: etxmljg@REDACTED > > > Subject: Re: Tcl/Tk > > > Cc: erlang-questions@REDACTED > > > Mime-Version: 1.0 > > > > > > Ljung Magnus wrote: > > > >Like always when calling out for help you find part of the solution at the > > same > > > >instance. A simple way to get access to the Erlang libraries is to re-compile > > > >Tcl with a function call to them included in the sourcecode. > > > > > > That may work in this case, but not in general I think. Only objects > > > (i.e. .o files) in an archive that satisfy unresolved references will be > > > included with the binary, thus objects that are only called from your > > > loadable object will still be missing at runtime. If it works, it's > > > because the function you call directly from tcl in turn, directly or > > > indirectly, calls enough other functions to pull in all the needed > > > objects. Plus of course it will make the erl_interface libraries > > > "bundled" with tcl rather than with your shared object, which is > > > probably not what you wanted. > > > > > > > This is not the > > > >best solution but gives me the possibility to proceed until I find something > > > >better. > > > > > > Did you even try the trivial one I suggested? Here's a simplified > > > demonstration to show that it works (and that Per B is partially > > > wrong:-) - run on Solaris 2.6 (I assume Solaris from your -R, you didn't > > > say what OS it was): > > > > > > % cat app.c > > > foo(){erl_init_nothreads();} > > > % gcc -O2 -shared -fPIC -L/usr/local/lib/erlang/lib/erl_interface-3.2/lib > > -lerl_interface app.c -o app.so > > > % ls -l app.so > > > -rwxr-xr-x 1 per 23836 Mar 28 09:51 app.so > > > % nm app.so | grep erl_init_nothreads > > > [82] | 0| 0|NOTY |GLOB |0 |UNDEF |erl_init_nothreads > > > % gcc -O2 -shared -fPIC app.c > > -L/usr/local/lib/erlang/lib/erl_interface-3.2/lib -lerl_interface -o app.so > > > % ls -l app.so > > > -rwxr-xr-x 1 per 124804 Mar 28 09:52 app.so > > > % nm app.so | grep erl_init_nothreads [187] > > | 7832| 24|FUNC |GLOB |0 |10 |erl_init_nothreads > > > > > > > > > >Your suggestion to recompile the Erlang libraries to shared ones sounds like > > the > > > >way forward to make the solution more seamless. > > > > > > As I wrote, it has different properties: The shared object will be > > > smaller, but the erl_interface libraries have to be around - and > > > findable by the runtime linker - at runtime. The tradeoff isn't > > > clear-cut, it depends e.g. on what you intend to do with the shared > > > object distribution-wise. > > > > > > --Per Hedeland > > > per@REDACTED From etxmljg@REDACTED Tue Mar 28 12:47:02 2000 From: etxmljg@REDACTED (Ljung Magnus) Date: Tue, 28 Mar 2000 12:47:02 +0200 (MET DST) Subject: Tcl/Tk-works now Message-ID: <200003281047.MAA02029@kkb3> Hi Per! It works after your last advice! Thank you all for the help. //Magnus > Subject: Re: Tcl/Tk > To: Ljung Magnus > Cc: per@REDACTED, erlang-questions@REDACTED, gordon.beaton@REDACTED, per.bohlin@REDACTED > MIME-version: 1.0 > Content-transfer-encoding: 7bit > X-Accept-Language: en > > Hi again Magnus. > > I don't know if I dare to put in an other theory here > but... > > Could it be that the tcl library is not compiled to have position > independent code? > Since you should alreaddy have everything in there when runing tcl > you could try to just remove -ltcl from your compilation command. > > /Per Bohlin > > Ljung Magnus wrote: > > > > Hi Per, > > > > I tried the simple fix but could not get it to work. > > Get problems with the Tcl library: > > gcc -O2 -shared -fPIC app.c -I/EDUP/Tcl/0/include/ > > -I/EDUP/Otp/0/lib/erl_interface-3.2/include -L/EDUP/Tcl/0/lib > > -L/EDUP/Otp/0/lib/erl_interface-3.2/lib \ > > -lerl_interface -lei -lm -ltcl -o app.so > > /EDUP/Tcl/0/lib/libtcl.a(tclAsync.o) > > 0x180 > > /EDUP/Tcl/0/lib/libtcl.a(tclAsync.o) > > 0x20 > > /EDUP/Tcl/0/lib/libtcl.a(tclAsync.o) > > ld: fatal: relocations remain against allocatable but non-writable sections > > > > You're probably correct that only my function call added in the Tcl source code > > will work but not the rest of the library functions...too bad. > > Solaris 2.6 is the OS used and any help on how to make the Erlang libraries > > shared assuming available object code? > > > > The application is for a Tcl/Tk program handling automatic tests of a Erlang > > node. This application adds a device package for the Network Elements so a > > configuration of the installation site is simpler than requiring a specific > > version of Tcl. Getting shared Erlang libraries would thus be better if there > > are no other solution. > > > > //Magnus > > > > P.S I do not subsrcibe to the mailing list yet so please send CC with the answer > > to me. > > > > > To: etxmljg@REDACTED > > > Subject: Re: Tcl/Tk > > > Cc: erlang-questions@REDACTED > > > Mime-Version: 1.0 > > > > > > Ljung Magnus wrote: > > > >Like always when calling out for help you find part of the solution at the > > same > > > >instance. A simple way to get access to the Erlang libraries is to re-compile > > > >Tcl with a function call to them included in the sourcecode. > > > > > > That may work in this case, but not in general I think. Only objects > > > (i.e. .o files) in an archive that satisfy unresolved references will be > > > included with the binary, thus objects that are only called from your > > > loadable object will still be missing at runtime. If it works, it's > > > because the function you call directly from tcl in turn, directly or > > > indirectly, calls enough other functions to pull in all the needed > > > objects. Plus of course it will make the erl_interface libraries > > > "bundled" with tcl rather than with your shared object, which is > > > probably not what you wanted. > > > > > > > This is not the > > > >best solution but gives me the possibility to proceed until I find something > > > >better. > > > > > > Did you even try the trivial one I suggested? Here's a simplified > > > demonstration to show that it works (and that Per B is partially > > > wrong:-) - run on Solaris 2.6 (I assume Solaris from your -R, you didn't > > > say what OS it was): > > > > > > % cat app.c > > > foo(){erl_init_nothreads();} > > > % gcc -O2 -shared -fPIC -L/usr/local/lib/erlang/lib/erl_interface-3.2/lib > > -lerl_interface app.c -o app.so > > > % ls -l app.so > > > -rwxr-xr-x 1 per 23836 Mar 28 09:51 app.so > > > % nm app.so | grep erl_init_nothreads > > > [82] | 0| 0|NOTY |GLOB |0 |UNDEF |erl_init_nothreads > > > % gcc -O2 -shared -fPIC app.c > > -L/usr/local/lib/erlang/lib/erl_interface-3.2/lib -lerl_interface -o app.so > > > % ls -l app.so > > > -rwxr-xr-x 1 per 124804 Mar 28 09:52 app.so > > > % nm app.so | grep erl_init_nothreads [187] > > | 7832| 24|FUNC |GLOB |0 |10 |erl_init_nothreads > > > > > > > > > >Your suggestion to recompile the Erlang libraries to shared ones sounds like > > the > > > >way forward to make the solution more seamless. > > > > > > As I wrote, it has different properties: The shared object will be > > > smaller, but the erl_interface libraries have to be around - and > > > findable by the runtime linker - at runtime. The tradeoff isn't > > > clear-cut, it depends e.g. on what you intend to do with the shared > > > object distribution-wise. > > > > > > --Per Hedeland > > > per@REDACTED From tobbe@REDACTED Tue Mar 28 14:32:50 2000 From: tobbe@REDACTED (Torbjorn Tornkvist) Date: 28 Mar 2000 14:32:50 +0200 Subject: "bug" in inet_parse:domain/1 Message-ID: Apparently, some registered domain names start with a figure, but: 1> inet_parse:domain("4u.com"). false 2> inet_parse:domain("u.com"). true /Tobbe From jamesh@REDACTED Tue Mar 28 18:01:33 2000 From: jamesh@REDACTED (James Hague) Date: Tue, 28 Mar 2000 10:01:33 -0600 Subject: Speed of floating point math Message-ID: <3.0.32.20000328100133.00d9dd3c@volition-inc.com> Consider this simple function: mag_squared(X,Y,Z) -> X*X + Y*Y + Z*Z. and this little test program: mag_test(0) -> ok; mag_test(N) -> mag_squared(0, 1, 0), mag_test(N-1). This takes a barely noticible amount of time for mag_test(100000), less than 1/8 second. Now change the last line to this: mag_test(N) -> mag_squared(0.0, 1.0, 0.0), mag_test(N-1). Now mag_test(100000) takes 4 seconds on the same machine; at least 32 times slower. Adding type guards to mag_squared makes no difference. I haven't torn into the runtime yet, but it's difficult to come up with a 32x difference. Are floating point values being heap allocated? Is most of the loop being optimized away in the integer version because the arguments to mag_squared are constants? An interesting puzzle! From rv@REDACTED Tue Mar 28 18:20:07 2000 From: rv@REDACTED (Robert Virding) Date: Tue, 28 Mar 2000 18:20:07 +0200 Subject: Speed of floating point math In-Reply-To: Your message of "Tue, 28 Mar 2000 10:01:33 MDT." <3.0.32.20000328100133.00d9dd3c@volition-inc.com> Message-ID: <200003281620.SAA12359@trana.bluetail.com> James Hague writes: >Consider this simple function: > >mag_squared(X,Y,Z) -> X*X + Y*Y + Z*Z. > >and this little test program: > >mag_test(0) -> ok; >mag_test(N) -> mag_squared(0, 1, 0), mag_test(N-1). > >This takes a barely noticible amount of time for mag_test(100000), less >than 1/8 second. Now change the last line to this: > >mag_test(N) -> mag_squared(0.0, 1.0, 0.0), mag_test(N-1). > >Now mag_test(100000) takes 4 seconds on the same machine; at least 32 times >slower. Adding type guards to mag_squared makes no difference. I haven't >torn into the runtime yet, but it's difficult to come up with a 32x >difference. Are floating point values being heap allocated? Is most of >the loop being optimized away in the integer version because the arguments >to mag_squared are constants? The main reason is that floats are heap allocated. Type guards are only used for determining if a clause is selected, at the moment they are not used for optimisation. So far the speed, or rather lack of, of floating point arithmetic has not really been a problem. I think that very few applications use floats. Robert From vances@REDACTED Tue Mar 28 19:17:12 2000 From: vances@REDACTED (Vance Shipley) Date: Tue, 28 Mar 2000 12:17:12 -0500 Subject: Tcl/Tk In-Reply-To: <200003280806.e2S86Iw26851@super.du.uab.ericsson.se> Message-ID: Here at Motivity we became frustrated with the lack of direction in the support of graphical user interfaces and took a course which sounds very similiar to what is being discussed here. We have built a Tcl/Tk extension to provide messaging into Erlang. It is a dynamically linked library which handles setting up connections to Erlang processes and translating messages. It's really a bridge from the Tcl script level into the erl_interface functions. Using this approach we can write user interface programs in native Tcl/Tk and run them on X-Windows/MS-Windows machines with no Erlang/OTP installed at all. The communication from the management station to the server is native Erlang messaging. We have ported the mines application example over to use this approach and intend to share this soon. Real work is keeping us busy elsewhere for the moment. :) -Vance Vance Shipley Motivity Telecom Inc. From pan@REDACTED Wed Mar 29 11:41:28 2000 From: pan@REDACTED (Patrik Nyblom) Date: Wed, 29 Mar 2000 11:41:28 +0200 Subject: Changing Solaris environment variables so os:getenv/1 gets the ne w References: Message-ID: <38E1CFC8.7302C2F@erix.ericsson.se> Hi, Sean Hinde wrote: > Thanks Peter: > > > Try os:putenv(Var, Value). > > > > /Peter > > An intriuging answer. There is no documentation on this, it is not in module > os source, and m(os). returns: > > Exports: > cmd/1 > find_executable/1 > find_executable/2 > handle_call/3 > handle_info/2 > init/1 > module_info/0 > module_info/1 > start_link/0 > terminate/2 > type/0 > version/0 > > I guess it is a BIF. I must look through the source sometime and see what > other goodies are in there. It is "technically" a BIF. Unfortunately such creatures does not show up when doing a Module:module_info() (or an m(Module)). They *should* be documented though. This may be a deliberate "documentation bug", as the result of os:putenv/2 does *not* always show up when using os:cmd/1 (due to the fact that the shell is "kept" between commands). Both the os:cmd problem and the missing documentation should, and will, be fixed. Until recently, there were a lot of undocumented BIF's in the system. We now try to have all BIF's documented and instead warn in the documentation if the BIF is likely to change in the future or is strange in some other way. We seem to have overlooked this one. /Patrik > > > Cheers, > Sean From bjarne@REDACTED Wed Mar 29 14:13:23 2000 From: bjarne@REDACTED (Bjarne =?iso-8859-1?Q?D=E4cker?=) Date: Wed, 29 Mar 2000 14:13:23 +0200 Subject: On-line archive Message-ID: <38E1F363.98D26FB3@erix.ericsson.se> ERROR The requested URL could not be retrieved -------------------------------------------------------------------- While trying to retrieve the URL: http://www.erlang.org/ml-archive/erlang-questions The following error was encountered: Unable to forward this request at this time. This request could not be forwarded to the origin server or to any parent caches. The most likely cause for this error is that: The cache administrator does not allow this cache to make direct connections to origin servers, and All configured parent caches are currently unreachable. Your cache administrator is lsa@REDACTED ---------------------------------------------------------------------- Generated Wed, 29 Mar 2000 12:12:52 GMT by proxy.du.uab.ericsson.se (Squid/2.3.STABLE1) From per@REDACTED Wed Mar 29 20:10:19 2000 From: per@REDACTED (Per Hedeland) Date: Wed, 29 Mar 2000 20:10:19 +0200 (MET DST) Subject: On-line archive In-Reply-To: <38E1F363.98D26FB3@erix.ericsson.se> References: <38E1F363.98D26FB3@erix.ericsson.se> Message-ID: <200003291810.UAA04543@aalborg.du.uab.ericsson.se> Um, Bjarne, how shall I put this... - sending mail to erlang-questions is probably not the most efficient way for *you* to get help if you have problems getting to the archive.:-) Please try the address in the error message next time...:-) --Per Bjarne D?cker wrote: >ERROR > >The requested URL could not be retrieved > >-------------------------------------------------------------------- > >While trying to retrieve the URL: >http://www.erlang.org/ml-archive/erlang-questions > >The following error was encountered: > > Unable to forward this request at this time. > >This request could not be forwarded to the origin server or to any >parent caches. The most likely cause for this >error is that: > > The cache administrator does not allow this cache to make direct >connections to origin servers, and > All configured parent caches are currently unreachable. > >Your cache administrator is lsa@REDACTED > >---------------------------------------------------------------------- > >Generated Wed, 29 Mar 2000 12:12:52 GMT by proxy.du.uab.ericsson.se >(Squid/2.3.STABLE1) > From torsten@REDACTED Wed Mar 29 23:39:46 2000 From: torsten@REDACTED (Torsten Sinnemann) Date: Wed, 29 Mar 2000 13:39:46 -0800 Subject: I am trying to run eddie and am getting an erlang error erl_connect failed what am I doing wrong? Message-ID: From mikpe@REDACTED Fri Mar 31 12:38:20 2000 From: mikpe@REDACTED (Mikael Pettersson) Date: Fri, 31 Mar 2000 12:38:20 +0200 (MET DST) Subject: public release of HiPE native-code Erlang compiler Message-ID: <200003311038.MAA02609@harpo.it.uu.se> ================================================================= PUBLIC RELEASE OF HiPE ================================================================= We, the HiPE group at Uppsala University, Sweden are proud to announce the first public release of: Open Source High-Performance Erlang (HiPE) System Version 0.92 What is HiPE ? ============== HiPE is a SPARC-V9 native-code compiler for the Erlang programming language, currently based on Open Source Erlang V47.4.1. HiPE is a complete implementation of the Erlang language, offers flexible integration between emulated and native code, and efficiently supports features crucial for Erlang's application domain, such as concurrency. The distribution of HiPE includes the Open Telecom Platform (OTP) libraries (except "orber" and "mnesia_session"). Who should be interested in HiPE ? ================================== Developers who are already using Open Source Erlang on a SPARC architecture. Depending on the characteristics of the application, our measurements indicate performance improvements ranging from 30% (for really big applications) up to an order of magnitude in small benchmarks. What is needed to install HiPE ? ================================ - A SPARC-V9 based machine running Solaris 2.x - GNU `make' for the build procedure. (Solaris `make' will not work.) - An ANSI-C compiler which understands // comments is required. The GNU C compiler is recommended. Where can I find HiPE ? ======================= HiPE is freely available at: http://www.csd.uu.se/projects/hipe/osh/download.shtml where further information about HiPE also can be found. - Erik Johansson, Mikael Pettersson, and Kostis Sagonas