[Ur] callbacks from C FFI (again)

Adam Chlipala adamc at csail.mit.edu
Sun Jan 5 13:10:48 EST 2014


On 01/03/2014 04:39 PM, Sergey Mironov wrote:
> Here is how I view the uw_trigger_task("name_of_task") you are suggesting:
> [...]
>
> This time JobFFI.run remembers task name and calls uw_trigger_task
> upon completion. Do I understand your idea correctly?
>    

Yes, that's what I meant.

> I have doubts. In my view, the whole concept of tasks is a kind of
> compromise. It covers some certain cases of server-side procedures
> without introducing a  low-level bindings to operating system's API of
> threads, processes, signals and everything. It is simply not possible
> to cover all cases with tasks. You as an author should stop extending
> it in some point and say "everything else is beyond the scope of
> Ur/Web, use FFI if tasks are not enough". And, in fact, you did it.

I can certainly see the appeal of that position, especially to me. ;)

> I think it is better to direct efforts into improvement of the FFI
> interface and urweb API because we will need them anyway. If I only
> had methods for
>
> 1) clone the context to use it with a new thread inside an FFI
> 2) call the url handler (I already know that `uw_begin' or
> `uw_get_app(ctx)->handle(ctx, uri)' may help me here)
>    

I think I'm basically on board with this proposal, but there is it least 
one potential complication that seems worth bringing up.

Any Ur/Web code may encounter a benign exception requiring transaction 
restart.  The canonical example is a serialization failure from 
optimistic SQL concurrency.  Your suggestions above don't make it clear 
how transactions should be handled in general, including where to jump 
back to when a transaction needs restarting.

For simplicity's sake, what do you think of implementing the following 
two functions instead?
1) clone context but don't start a transaction for it (note that this 
also opens a database connection, checks the schema, and creates 
prepared statements!)
2) given a context and a URI, run the associated Ur/Web code in that 
context in a new transaction associated only with this operation

> PS
> By the way, I am missing the ability to pass Ur/Web records to/from
> FFI. Is it hard to implement? I imagine they are represented with a
> plain C structures in the transaction's memory pool so may it be that
> it is not that hard?
>    

C struct "subtyping" works nominally: two identically defined structs 
with different names are considered different types.  Thus, one job of 
the Ur/Web compiler is to group together all uses of structurally 
equivalent record types, defining one C struct for each.

Because of this, it's hard to support _elegant_ use of Ur/Web records in 
C FFI code.  You should be safe redefining the struct type with a 
different name and casting as necessary, though.  This would require 
some changes to the Ur/Web compiler to allow things that it currently 
thinks are scary.

My main recommendation, though, is to do like this for a record that 
needs to cross the Ur-C boundary.  This would be code in an FFI .urs file:
     type myrecord
     val myrecord : int -> string -> myrecord
     val getInt : myrecord -> int
     val getString : myrecord -> string




More information about the Ur mailing list