File Server erlang response - concurrency

I am trying to follow the very first example given in the Programming Erlang, Software for a concurrent world by Joe Armstrong. Here is the code:
-module(afile_server).
-export([start/1,loop/1]).
start(Dir) -> spawn(afile_server,loop,[Dir]).
loop(Dir) ->
receive
{Client, list_dir} ->
Client ! {self(), file:list_dir(Dir)};
{Client, {get_file, File}} ->
Full = filename:join(Dir,File),
Client ! {self(), file:read_file(Full)}
end,
loop(Dir).
Then I run this in the shell:
c(afile_server).
FileServer = spawn(afile_server, start, ".").
FileServer ! {self(), list_dir}.
receive X -> X end.
In the book a list of the files is returned as expected however in my shell it looks as if the program has frozen. Nothing gets returned yet the program is still running. I'm not familiar at all with erlang however I can understand how this should work.
I'm running this in Windows 7 64-bit. The directory is not empty as it contains a bunch of other erlang files.

So... what start/1 function is doing here? It's spawning a process which starts from loop/1 and you don't just run it in your shell but spawning it too! So you have a chain of two spawned processes and process under FileServer dies imiedietly because its only job is to spawn actual file server which pid is unknown to you.
Just change line:
FileServer = spawn(afile_server, start, ".").
to:
FileServer = afile_server:start(".").

The drawing below illustrates Lukasz explanation.

Related

Why won't node zero execute some of the write statements to a log file

I have a production job where I use two nodes (0=master and 1=slave) via OPENMPI and all the threads on each node via OPENMP.
I submit the job on the master.
Job opens a disk file on master to log some info. ( I see same file is opened on slave as well during the run)
I have statements like
write(lu,*) 'pid=',pid,' some text'
and
write(6, *) 'pid=',pid,' some text'
one after the other. (unit 6 is the stdout -screen- in gfortran).
I see on screen that both statements are printed one after the other ( pid=0 and pid=1 ).
Strangely enough most (not all) of master prints (pid=0) on the log file are absent.
This is puzzling. I would like to learn the rule. I thought both master and slave share the logfile.
I have a host file with two hosts each requesting 32 threads ( via slots and max-slots commands ) and I am running the following command as a script
miprun --hostfile hostfile --map-by node:pe32 myexecutable
I will appreciate if some expert can shed light on the issue.

Not receiving data in LCP(PPPoS) phase over UART(ESP-32 -> Sim7600)

On my ESP32 I am having trouble creating a working PPP interface to my ISP.
I am using an ESP-32 Ethernet kit and have it hooked up to a Simcom EVB Kit with a Sim7600G chip.
With this hardware I am using ESP-IDF in combination with LWIP to get the PPP connection going.
At first I have to send all the corresponding AT commands to make sure it is actually ready for a PPP connection.
These AT Commands are the following:
AT+CGDCONT=1,"IP","<APN>"
AT+CGACT=1,1
AT+CREG? <Must be 0,5 -> Registered and Roaming>
ATD*99***1# -> I receive "Connect 152000" and start the PPP phase.
After I received the Connect 152000 as a response, I start the PPP connection.
m_pPpp = pppapi_pppos_create(&netif, pppos_output_cb, ppp_link_status_cb, nullptr);
pppapi_set_default(m_pPpp);
pppapi_set_auth(m_pPpp, PPPAUTHTYPE_PAP, "", "");
err_t err = ppp_connect(m_pPpp, 0);
This is the output of the corresponding code:
ppp phase changed[2]: phase=0
ppp_connect[2]: holdoff=0
ppp phase changed[2]: phase=3
pppos_connect: unit 2: connecting
ppp_start[2]
ppp phase changed[2]: phase=6
pppos_send_config[2]: out_accm=FF FF FF FF
ppp_send_config[2]
pppos_recv_config[2]: in_accm=FF FF FF FF
ppp_recv_config[2]
ppp: auth protocols: PAP=1
sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0xcd3e2cad> <pcomp> <accomp>]
I: pppos_output callback called
I: ppp_output_cb() len = 45
W: ip4addr: 0.0.0.0
W: his_ipaddr: 0.0.0.0
W: netmask: 255.255.255.255
pppos_write[2]: len=24
ppp_start[2]: finished
As far as I can see, it goes through a couple of phases regarding the PPP connection.
Phase 0(dead, obviously)
Phase 3(initialize)
Phase 6(Establish).
It will not continue after this. I see the pppos_output callback is being called, which is supposed to happen. As far as I understand this function is so you can write the PPP-data towards your UART device.
Seperately I have a task running in the background to poll my UART device for written data so I can write this to the pppos_input function. I never receive any data...
I honestly have no idea where if I am missing something or how to troubleshoot this.
Also the LWIP documentation is quite plain and is missing examples, which makes it even harder.
Additional things I have tried:
AT+CGDCONT=1,"PPP","APN". <- This will result in the Sim7600 never connecting and remains searching. Should I use these PDP settings or stay with IP?
Applied the above AT command and tried starting the PPP phase, hoping it would result in somehow connecting...
I have not found the solution to this problem with the mentioned frameworks. Instead I reverted to another dependency from the ESP-IDF: esp-modem. I managed to get a working solution by following the pppos-client and modem-console examples within my current software.

How to perform a subroutine every 5 seconds?

I have a subroutine to check if a disk is mounted,
I would like to know how do I make this subroutine always run every 5 seconds.
thanks in advance!
on checkMyDiskIsMounted()
tell application "Finder"
activate
if exists disk "myDisk" then
--do anything
else
--do anything
end if
end tell
end checkMyDiskIsMounted
Using things like AppleScript's delay command, a shell utility such as sleep, or even a tight repeat loop should all be avoided, as those tend to block the user interface while they are running.
A repeating timer could be used to periodically poll, but instead of wasting time continually checking for something that may or may not happen, NSWorkspace can be used, as it provides notifications for exactly this kind of thing (amongst others). The way this works is your application registers for the particular notifications that it is interested in, and the specified handler is called when (if) the event occurs.
Note that the following script includes statements so that it can be run from the Script Editor as an example - observers are added to the application instance, and will stick around until they are removed or the application is quit:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "AppKit"
use scripting additions
on run -- or whatever initialization handler
# set up notifications
tell current application's NSWorkspace's sharedWorkspace's notificationCenter
its addObserver:me selector:"volumeMounted:" |name|:(current application's NSWorkspaceDidMountNotification) object:(missing value)
its addObserver:me selector:"volumeUnmounted:" |name|:(current application's NSWorkspaceDidUnmountNotification) object:(missing value)
end tell
end run
on volumeMounted:aNotification -- do something on mount
set volumeName to (NSWorkspaceVolumeLocalizedNameKey of aNotification's userInfo) as text
display notification "The volume " & quoted form of volumeName & " was mounted." with title "Volume mounted" sound name "Hero" -- or whatever
end volumeMounted:
on volumeUnmounted:aNotification -- do something on unmount
set volumeName to (NSWorkspaceVolumeLocalizedNameKey of aNotification's userInfo) as text
display notification "The volume " & quoted form of volumeName & " was unmounted." with title "Volume unmounted" sound name "Funk" -- or whatever
end volumeUnmounted:
Four options:
A repeat loop with delay as suggested by matt
repeat
-- code
delay 5
end repeat
A (stay open) applet with idle handler
on run
-- do intialiations
end run
on idle
-- code
return 5
end idle
An AppleScriptObjC notification like suggested by red_menace
A launchd agent observing the /Volumes folder
In favor of option 3 and 4 which inexpensively notify about a change the first two options which poll periodically are discouraged.

Erlang register error

I'm writing a program which will take two strings and concatenate them as a shared dropbox stimulation. I'm using code from a different application, which did a similar thing with a joint bank account, so the errors may be because I haven't changed some line of code properly but I just can't work out what’s wrong.
The code is written in two separate files and they link together, the basic dropbox is first and then the code which links that and displays the answer is below.
-module(dropbox).
-export([account/1, start/0, stop/0, deposit/1, get_bal/0, set_bal/1]).
account(Balance) ->
receive
{set, NewBalance} ->
account(NewBalance);
{get, From} ->
From ! {balance, Balance},
account(Balance);
stop -> ok
end.
start() ->
Account_PID = spawn(dropbox, account, [0]),
register(account_process, Account_PID).
stop() ->
account_process ! stop,
unregister(account_process).
set_bal(B) ->
account_process ! {set, B}.
get_bal() ->
account_process ! {get, self()},
receive
{balance, B} -> B
end.
deposit(Amount) ->
OldBalance = get_bal(),
NewBalance = OldBalance ++ Amount,
set_bal(NewBalance).
-module(dropboxtest).
-export([start/0, client/1]).
start() ->
dropbox:start(),
mutex:start(),
register(tester_process, self()),
loop("hello ", "world", 100),
unregister(tester_process),
mutex:stop(),
dropbox:stop().
loop(_, _, 0) ->
true;
loop(Amount1, Amount2, N) ->
dropbox:set_bal(" "),
spawn(dropboxtest, client, [Amount1]),
spawn(dropboxtest, client, [Amount2]),
receive
done -> true
end,
receive
done -> true
end,
io:format("Expected balance = ~p, actual balance = ~p~n~n",
[Amount1 ++ Amount2, dropbox:get_bal()]),
loop(Amount1, Amount2, N-1).
client(Amount) ->
dropbox:deposit(Amount),
tester_process ! done.
This is the error which I'm getting, all of the other ones I've managed to work out but I don't quite get this one so I'm not sure how to solve it.
** exception error: bad argument
in function register/2
called as register(account_process,<0.56.0>)
in call from dropbox:start/0 (dropbox.erl, line 16)
in call from dropboxtest:start/0 (dropboxtest.erl, line 5)
Also I know that this is going to come up with errors due to concurrency issues, I need to show these errors to prove what’s wrong before I can fix it. Some of the functions haven't been changed from the bank program hence balance etc.
As per the documentation, register can fail with badarg for a number of reasons:
If PidOrPort is not an existing local process or port.
If RegName is already in use.
If the process or port is already registered (already has a name).
If RegName is the atom undefined.
In this case I suspect it's the second reason, that there's already a process with the name account_process, from a previous run. You could try restarting the Erlang shell, or you could change the spawn call in dropbox:start to spawn_link, which would cause the old process to crash in case of any error in the shell.

Lwt leaking file descriptors, not sure if bug or my code

(Cross posted to lwt github issues)
I have boiled down my usage to this code sample which will leak file descriptors.
say you have:
#require "lwt.unix"
open Lwt.Infix
let echo ic oc = Lwt_io.(write_chars oc (read_chars ic))
let program =
let server_address = Unix.(ADDR_INET (inet_addr_loopback, 2000)) in
let other_addr = Unix.(ADDR_INET (inet_addr_loopback, 2001)) in
let server = Lwt_io.establish_server server_address begin fun (tcp_ic, tcp_oc) ->
Lwt_io.with_connection other_addr begin fun (nc_ic, nc_oc) ->
Lwt_io.printl "Created connection" >>= fun () ->
echo tcp_ic nc_oc <&> echo nc_ic tcp_oc >>= fun () ->
Lwt_io.printl "finished"
end
|> Lwt.ignore_result
end
in
fst (Lwt.wait ())
let () =
Lwt_main.run program
and then you create a simple server with:
nc -l 2001
and then let's start up the OCaml code with
utop example.ml
and then open up a client
nc localhost 2000
blah blah
^c
Then looking at the connections for port 2000 using lsof, we see
ocamlrun 71109 Edgar 6u IPv4 0x7ff3e309cb80aead 0t0 TCP 127.0.0.1:callbook (LISTEN)
ocamlrun 71109 Edgar 7u IPv4 0x7ff3e309c9dc8ead 0t0 TCP 127.0.0.1:callbook->127.0.0.1:54872 (CLOSE_WAIT)
In fact for each usage of nc localhost 2000, we'll get a leftover CLOSE_WAIT record from the lsof usage.
Eventually this will lead to the system running out of file descriptors, which will MOST annoyingly not crash the program, but will lead to Lwt to just hang.
I can't tell if I am doing something wrong or if this is a genuine bug, in any case this is a serious bug for me and I run out of file descriptors within 10 hours...
EDIT: It seems to me that the problem is that one side of the connection is closed but the other isn't, I would have thought that with_connection should cleanup/close up whenever either side closes, aka whenever nc_ic or nc_oc close.
EDIT II: I have tried every which way where I manually close the descriptors with Lwt_io.close, but I still have the CLOSE_WAIT message.
EDIT III: Even used Lwt_unix.close on a raw fd given to with_connection's optional fd argument with similar bad results.
EDIT IV: Most insidious is if I use Lwt_daemon.daemonize, then this problem seemingly goes away
First, it is not clear why you use join <&> instead of choose <?>. I guess the connection should be closed if one of both sides wants to close it.
Concerning CLOSE_WAIT: it is half-closed connection from utop server to nc client.
A TCP connection consists of two half-connections, and they are closed independently. The connection from nc client to utop server was closed by nc due to Ctrl-C. But you have to explicitly close the opposite connection on server side by closing output stream. I'm not sure why Lwt.establish_server doesn't close it automatically. Possible, this is a design issue.
This works for me on CentOS 7:
Lwt_io.printl "Created connection" >>= fun () ->
echo tcp_ic nc_oc <?> echo nc_ic tcp_oc >>= fun () ->
Lwt_io.close tcp_oc >>= fun () ->
Lwt_io.printl "finished"
Also, there is a simplified code snippet to reproduce the issue:
#require "lwt.unix"
let program =
let server_address = Unix.(ADDR_INET (inet_addr_loopback, 2000)) in
let _server = Lwt_io.establish_server server_address begin fun (ic, oc) ->
(* Lwt_io.close oc |> Lwt.ignore_result; *) ()
end
in
fst (Lwt.wait ())
let () =
Lwt_main.run program
Run nc localhost 2000 several times to get connections in CLOSE_WAIT state. Uncomment the code to fix the issue.
The underlying problem, at the time this question was asked, was that Lwt_io.establish_server did not make any effort at all to close the file descriptors associated with tcp_ic and tcp_oc. While this could (and should) have been addressed by users closing them manually, it was a weird and unexpected behavior.
The new Lwt_io.establish_server, available since Lwt 3.0.0, does try to close tcp_ic and tcp_oc automatically. To permit this, it has a slightly different type signature for the callback: the callback must return a promise, which you should resolve when tcp_ic/tcp_oc are not needed anymore. (EDIT) In practice, this means you just write your callback in natural Lwt style, and completion of the last Lwt operation will close the channels.
The new API also internally calls Lwt.async for running your callback, so you don't have to call that or Lwt.ignore_result.
You can still close the tcp_ic and tcp_oc manually in the callback, to write your own error handlers, which can be as elaborate as you please. The second automatic, internal close inside the new Lwt_io.establish_server won't have any harmful effect.
The new API was the eventual result of the parallel discussion of this question in the Lwt issue #208.
If someone would like the old, painful behavior, perhaps to reproduce the issue in the question, the old API is available for a while longer under the name Lwt_io.Versioned.establish_server_1.