synchronous Socket.bind

13 views
Skip to first unread message

Fabrice Le Fessant

unread,
Apr 28, 2016, 5:01:54 AM4/28/16
to ocaml...@googlegroups.com
Hi,

  I am using a little wrapper around Lwt to hide its monadic style (https://github.com/OCamlPro/ocp-cplugins/tree/master/libs/ocplib-lwt-wrapper), but now, I would like to use the same one on top of Async.

  Currently, when binding a socket to an address, I immediately return the address to which it was bound: this is useful to get the port chosen by the system when the provided port is 0. Is there a way to call the equivalent bind operation in Async in a synchronous way, i.e. without deferring the operation ? (I didn't know "bind" could block, but if it is the case, I would prefer to block at that point than using a continuation...). 

In general, is there a synchronous API for Async, i.e. for basic operations in the API, a way to call the blocking function instead of the asynchronous one ?

--Fabrice
PS: I had a look at async-lwt, it does not look maintain, was it a successful experiment ?


Arseniy Alekseyev

unread,
Apr 28, 2016, 6:38:55 AM4/28/16
to ocaml...@googlegroups.com
Generally a function that can help change async call into a blocking one is 

  Async.Std.Thread_safe.block_on_async_exn : (unit -> 'a Deferred.t) -> 'a

That said, this function comes with some known caveats, such as

- It can not be called from within async
- (as a consequence of the above) it can not be nested.

--
You received this message because you are subscribed to the Google Groups "ocaml-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ocaml-core+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Fabrice Le Fessant

unread,
Apr 28, 2016, 8:20:34 AM4/28/16
to ocaml...@googlegroups.com
Thanks ! 

On Thu, Apr 28, 2016 at 12:38 PM Arseniy Alekseyev <aalek...@janestreet.com> wrote:
- It can not be called from within async
- (as a consequence of the above) it can not be nested.

That's a strong assumption for my library. 

Would the following code work instead ?

let create_server sockaddr =
  ...
  let sock = Socket.create Socket.Type.tcp in
  let fd = Socket.fd sock in
  let ufd = Fd.file_descr_exn fd in
  Unix.bind ufd sockaddr; (* Unix is the otherlibs/unix/ library here, not Async.Unix *)
  Unix.listen ufd 20;
  let s = Socket.of_fd fd Socket.Type.tcp in
  upon (Socket.accept s)  (function (* HANDLE THE CONNECTION *) )


--Fabrice 

Yaron Minsky

unread,
Apr 28, 2016, 8:49:06 AM4/28/16
to ocaml...@googlegroups.com

Hiding the monadic nature of async is not an easy thing to do.  You can't do your own blocking inside of the async thread, since that prevents the async scheduler from running.  You can, however, have a separate synchronous thread which offloads work to async, as Arseniy proposed.  That should let you lift deferred-returning operations on the async side to blocking ones on your thread. 

Can you explain more about why this isn't suitable for your application?

y

--

Arseniy Alekseyev

unread,
Apr 28, 2016, 9:34:54 AM4/28/16
to ocaml...@googlegroups.com
> Would the following code work instead ?

I'm not familiar enough with the way Socket module works to answer the question: you should study the code of [Socket] to make sure it's happy to be created from a listening socket, but I can't see any obvious issues and the general approach of using the low-level blocking primitives from Core.Unix should work well.

Fabrice Le Fessant

unread,
Apr 28, 2016, 10:02:09 AM4/28/16
to ocaml...@googlegroups.com
On Thu, Apr 28, 2016 at 2:49 PM Yaron Minsky <ymi...@janestreet.com> wrote:

Hiding the monadic nature of async is not an easy thing to do.  You can't do your own blocking inside of the async thread, since that prevents the async scheduler from running.  You can, however, have a separate synchronous thread which offloads work to async, as Arseniy proposed.  That should let you lift deferred-returning operations on the async side to blocking ones on your thread. 

Can you explain more about why this isn't suitable for your application?

My problem is that it is not an application, but a library, so I cannot simply assume that the user will never try to create a server socket from a function inside an Async deferred action.

Anyway, I don't think that preventing the async scheduler from working during the Unix.bind will be a problem: establishing a server is usually the first action before starting other concurrent actions, and my lib is just a wrapper to ease programming of concurrent applications, it is not supposed to be used for high-performance networking...

--Fabrice

Yaron Minsky

unread,
Apr 28, 2016, 5:26:30 PM4/28/16
to ocaml...@googlegroups.com
On Thu, Apr 28, 2016 at 10:01 AM, Fabrice Le Fessant
<Fabrice.L...@inria.fr> wrote:
> On Thu, Apr 28, 2016 at 2:49 PM Yaron Minsky <ymi...@janestreet.com> wrote:
>>
>> Hiding the monadic nature of async is not an easy thing to do. You can't
>> do your own blocking inside of the async thread, since that prevents the
>> async scheduler from running. You can, however, have a separate synchronous
>> thread which offloads work to async, as Arseniy proposed. That should let
>> you lift deferred-returning operations on the async side to blocking ones on
>> your thread.
>>
>> Can you explain more about why this isn't suitable for your application?
>
> My problem is that it is not an application, but a library, so I cannot
> simply assume that the user will never try to create a server socket from a
> function inside an Async deferred action.

I think directly exposing Async (or LWT) operations in a synchronous
environment is a mistake, and will lead to confusing and buggy
behavior. I think you can write a library that doesn't expose any
deferreds or bind or other "wait-for-this-and-then-run" type
operations at all, and just does a simple, synchronous embedding of
those operations. Then, I think users can naively use that,
essentially just having Async as the engine for doing the IO. You can
even have some standard idioms and helpers for writing the wrappers.

But I don't see any other way of writing a library like this in a
reliable way.

> Anyway, I don't think that preventing the async scheduler from working
> during the Unix.bind will be a problem: establishing a server is usually the
> first action before starting other concurrent actions, and my lib is just a
> wrapper to ease programming of concurrent applications, it is not supposed
> to be used for high-performance networking...

I think this is a mistake. If you allow people to randomly block the
Async scheduler all over the place, you're going to get weird and hard
to debug situations, (maybe even deadlocks?). The library you
describe is not something I'd want to use for writing reliable
software. And I think Lwt and Async are similar in this regard.
Reply all
Reply to author
Forward
0 new messages