flounder: adding local, intra-domain backend (RPCs work only with rpc rx table)
authorAdam Turowski <adam.turowski@inf.ethz.ch>
Mon, 20 Feb 2017 15:26:41 +0000 (16:26 +0100)
committerAdam Turowski <adam.turowski@inf.ethz.ch>
Mon, 27 Feb 2017 10:38:08 +0000 (11:38 +0100)
Signed-off-by: Adam Turowski <adam.turowski@inf.ethz.ch>

18 files changed:
errors/errno.fugu
hake/ArchDefaults.hs
hake/Args.hs
hake/X86_64.hs
if/monitor.if
if/test.if
include/barrelfish/idc_export.h
lib/barrelfish/idc_export.c
lib/barrelfish/lmp_chan.c
lib/barrelfish/monitor_client.c
tools/flounder/BackendCommon.hs
tools/flounder/GCBackend.hs
tools/flounder/GHBackend.hs
tools/flounder/LMP.hs
tools/flounder/Local.hs [new file with mode: 0644]
tools/flounder/Main.lhs
tools/flounder/RPCClient.hs
usr/monitor/monitor_server.c

index 64f16b2..53fecac 100755 (executable)
@@ -474,6 +474,7 @@ errors mon_client MON_CLIENT_ERR_ {
 // errors generated by the Monitor
 errors monitor MON_ERR_ {
     failure IDC_BIND_NOT_SAME_CORE "Cannot perform IDC bind call: IREF is on another core",
+    failure IDC_BIND_LOCAL      "Cannot perform IDC bind call: intra-domain binding",
     failure INVALID_CORE_ID     "Core ID is invalid (out of range)",
     failure INVALID_IREF        "Invalid IREF for bind call",
     failure IREF_ALLOC          "Cannot allocate IREF, table full",
@@ -1247,7 +1248,6 @@ errors sfn SFN_ERR_{
     failure REGISTER_REGION      "Error registering a region",
     failure DEREGISTER_REGION    "Error deregistering a region",
     failure ALLOC_QUEUE          "Failure allocating queue",
-    failure ENQUEUE              "Failure during enqueue", 
-    failure QDRIVER              "Failure starting queue driver", 
+    failure ENQUEUE              "Failure during enqueue",
+    failure QDRIVER              "Failure starting queue driver",
 };
-
index ada9a79..4bb3864 100644 (file)
@@ -127,8 +127,8 @@ options arch archFamily = Options {
             optLdCxxFlags = ldCxxFlags arch,
             optLibs = stdLibs arch,
             optCxxLibs = stdCxxLibs arch,
-            optInterconnectDrivers = ["lmp", "ump", "multihop"],
-            optFlounderBackends = ["lmp", "ump", "multihop"],
+            optInterconnectDrivers = ["lmp", "ump", "multihop", "local"],
+            optFlounderBackends = ["lmp", "ump", "multihop", "local"],
             extraFlags = [],
             extraCxxFlags = [],
             extraDefines = [],
index 485356d..50d326a 100644 (file)
@@ -92,7 +92,7 @@ thcArchitectures = ["x86_64", "x86_32"]
 
 -- all known flounder backends that we might want to generate defs for
 allFlounderBackends
-    = [ "lmp", "ump", "ump_ipi", "loopback", "rpcclient", "msgbuf", "multihop", "ahci" ]
+    = [ "lmp", "ump", "ump_ipi", "loopback", "rpcclient", "msgbuf", "multihop", "ahci", "local" ]
 
 defaultBuildFn :: TreeDB -> String -> Args -> HRule
 defaultBuildFn _ f _ = 
index a98109c..ca60b3c 100644 (file)
@@ -63,8 +63,8 @@ options = (ArchDefaults.options arch archFamily) {
             optDefines = cDefines,
             optLdFlags = ldFlags,
             optLdCxxFlags = ldCxxFlags,
-            optInterconnectDrivers = ["lmp", "ump", "multihop"],
-            optFlounderBackends = ["lmp", "ump", "multihop"]
+            optInterconnectDrivers = ["lmp", "ump", "multihop", "local"],
+            optFlounderBackends = ["lmp", "ump", "multihop", "local"]
           }
 
 --
index 7a4eebc..c3c9826 100644 (file)
@@ -19,6 +19,9 @@ interface monitor "The monitor to client Interface" {
         iref iref,
         errval err);
 
+    message get_service_id_request(iref iref);
+    message get_service_id_reply(errval err, iref iref, uintptr service_id);
+
     /* TODO: move to monitor_blocking as RPC? */
     message boot_core_request(uint8 id, cap frame);
     message boot_core_reply(errval err);
index 5607ace..a837722 100644 (file)
@@ -13,4 +13,5 @@ interface test "Test interface" {
         message one_cap(uint32 arg, cap cap1);
         message caps(uint32 arg, cap cap1, cap cap2);
         message buf(uint8 buf[buflen, 2048]);
+        rpc basic_rpc(in uint32 arg, out uint32 result);
 };
index 7a3db3d..7168990 100644 (file)
@@ -22,6 +22,11 @@ __BEGIN_DECLS
 
 typedef void idc_export_callback_fn(void *st, errval_t err, iref_t iref);
 
+#ifdef CONFIG_INTERCONNECT_DRIVER_LOCAL
+typedef errval_t local_connect_callback_fn(void *st, void *binding,
+                                           void **ret_binding);
+#endif // CONFIG_INTERCONNECT_DRIVER_LOCAL
+
 #ifdef CONFIG_INTERCONNECT_DRIVER_LMP
 typedef errval_t lmp_connect_callback_fn(void *st, size_t buflen_words,
                                          struct capref endpoint,
@@ -49,6 +54,9 @@ struct idc_export {
 
     /* for each configured channel type, we need a binding-specific
      * connect callback */
+#ifdef CONFIG_INTERCONNECT_DRIVER_LOCAL
+    local_connect_callback_fn *local_connect_callback;
+#endif
 #ifdef CONFIG_INTERCONNECT_DRIVER_LMP
     lmp_connect_callback_fn *lmp_connect_callback;
 #endif
@@ -61,6 +69,7 @@ struct idc_export {
 };
 
 errval_t idc_export_service(struct idc_export *e);
+errval_t idc_get_service(iref_t iref, struct idc_export **e);
 void idc_export_init(void);
 
 __END_DECLS
index c8a2d43..07c52f6 100644 (file)
@@ -80,8 +80,66 @@ errval_t idc_export_service(struct idc_export *e)
     return SYS_ERR_OK;
 }
 
+
+struct idc_export_get_state {
+    struct event_queue_node qnode;
+    iref_t iref;
+    struct idc_export *e;
+    errval_t err;
+    struct monitor_binding *mb;
+};
+
+static void get_service_id_request_sender(void *arg)
+{
+    struct idc_export_get_state *st = arg;
+    struct monitor_binding *mb = st->mb;
+
+    /* Send alloc_iref request to the monitor */
+    errval_t err = mb->tx_vtbl.get_service_id_request(mb, NOP_CONT, st->iref);
+    if (err_is_ok(err)) {
+        event_mutex_unlock(&mb->mutex);
+    } else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+        err = mb->register_send(mb, mb->waitset,
+                                MKCONT(get_service_id_request_sender, st));
+        assert(err_is_ok(err)); // shouldn't fail, as we have the mutex
+    } else { // permanent error
+        event_mutex_unlock(&mb->mutex);
+    }
+}
+
+errval_t idc_get_service(iref_t iref, struct idc_export **e)
+{
+    struct idc_export_get_state st;
+
+    struct monitor_binding *mb = get_monitor_binding();
+    st.iref = iref;
+    st.e = NULL;
+    st.err = SYS_ERR_OK;
+    st.mb = mb;
+
+    // wait for the ability to use the monitor binding
+    event_mutex_enqueue_lock(&mb->mutex, &st.qnode,
+                             MKCLOSURE(get_service_id_request_sender, &st));
+    
+    errval_t error_var = SYS_ERR_OK;
+    errval_t err = wait_for_channel(mb->waitset, mb->message_chanstate + monitor_get_service_id_reply__msgnum, &error_var);
+    
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "in event_dispatch waiting for mem_serv binding");
+        return err_push(err, LIB_ERR_EVENT_DISPATCH);
+    }
+    
+    assert(err_is_ok(mb->rx_union.get_service_id_reply.err));
+    assert(iref == mb->rx_union.get_service_id_reply.iref);
+    assert(mb->rx_union.get_service_id_reply.service_id);
+    *e = (struct idc_export *)mb->rx_union.get_service_id_reply.service_id;
+    mb->receive_next(mb);
+    return err;
+}
+
 void idc_export_init(void)
 {
     struct monitor_binding *mcb = get_monitor_binding();
     mcb->rx_vtbl.alloc_iref_reply = alloc_iref_reply_handler;
+    mcb->rx_vtbl.get_service_id_reply = NULL;
 }
index 4a4c71e..9075b94 100644 (file)
@@ -173,14 +173,14 @@ static void send_bind_reply(void *arg)
     struct monitor_binding *b = st->b;
     errval_t err;
 
-    err = st->b->tx_vtbl.bind_lmp_reply_monitor(st->b, NOP_CONT, st->args.err,
-                                                st->args.mon_id, st->args.conn_id, 
+    err = b->tx_vtbl.bind_lmp_reply_monitor(b, NOP_CONT, st->args.err,
+                                                st->args.mon_id, st->args.conn_id,
                                                 st->args.ep);
     if (err_is_ok(err)) {
         event_mutex_unlock(&b->mutex);
         free(st);
     } else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
-        err = st->b->register_send(st->b, st->b->waitset,
+        err = b->register_send(b, b->waitset,
                                    MKCONT(send_bind_reply,st));
         assert(err_is_ok(err)); // shouldn't fail, as we have the mutex
     } else {
index e075466..d16ecbf 100644 (file)
@@ -125,6 +125,8 @@ static errval_t init_lmp_binding(struct monitor_lmp_binding *mcb,
     /* setup initial receive handlers */
     mcb->b.rx_vtbl = monitor_rx_vtbl;
 
+    // connect handlers
+    mcb->b.change_waitset(&mcb->b, mcb->b.waitset);
     return SYS_ERR_OK;
 }
 
@@ -335,7 +337,7 @@ static void monitor_rpc_bind_continuation(void *st_arg, errval_t err,
     struct bind_state *st = st_arg;
 
     if (err_is_ok(err)) {
-        struct monitor_blocking_rpc_client *r = 
+        struct monitor_blocking_rpc_client *r =
             malloc(sizeof(struct monitor_blocking_rpc_client));
         assert(r != NULL);
         err = monitor_blocking_rpc_client_init(r, b);
@@ -388,7 +390,7 @@ errval_t monitor_client_blocking_rpc_init(void)
     /* fire off a request for the iref for monitor rpc channel */
     struct monitor_binding *mb = get_monitor_binding();
     mb->rx_vtbl.get_monitor_rpc_iref_reply = get_monitor_rpc_iref_reply;
-    err = mb->tx_vtbl.get_monitor_rpc_iref_request(mb, NOP_CONT, 
+    err = mb->tx_vtbl.get_monitor_rpc_iref_request(mb, NOP_CONT,
                                                    (uintptr_t) &st);
     if (err_is_fail(err)) {
         return err_push(err, LIB_ERR_GET_MON_BLOCKING_IREF);
index c1193cb..a6f9d63 100644 (file)
@@ -303,7 +303,8 @@ binding_struct_init drv ifn binding_var waitset_ex tx_vtbl_ex = [
          | f <- ["tx_msgnum", "rx_msgnum", "tx_msg_fragment", "rx_msg_fragment",
                  "tx_str_pos", "rx_str_pos", "tx_str_len", "rx_str_len"]],
     C.Ex $ C.Assignment (C.FieldOf binding_var "incoming_token") (C.NumConstant 0),
-    C.Ex $ C.Assignment (C.FieldOf binding_var "outgoing_token") (C.NumConstant 0)]
+    C.Ex $ C.Assignment (C.FieldOf binding_var "outgoing_token") (C.NumConstant 0),
+    C.Ex $ C.Assignment (C.FieldOf binding_var "local_binding") (C.Variable "NULL") ]
 
 binding_struct_destroy :: String -> C.Expr -> [C.Stmt]
 binding_struct_destroy ifn binding_var
index a96b540..e0a8771 100644 (file)
@@ -24,6 +24,7 @@ import LMP (lmp_bind_type, lmp_bind_fn_name)
 import qualified UMP (bind_type, bind_fn_name)
 import qualified UMP_IPI (bind_type, bind_fn_name)
 import qualified Multihop (m_bind_type, m_bind_fn_name)
+import Local (local_init_fn_name)
 
 -- name of the bind continuation function
 bind_cont_name :: String -> String
@@ -428,6 +429,7 @@ data BindBackend = BindBackend {
 bind_backends :: String -> String -> [BindBackend]
 bind_backends ifn cont_fn_name = map (\i -> i ifn (C.Variable cont_fn_name))
                     [lmp_bind_backend,
+                     local_bind_backend,
                      ump_ipi_bind_backend,
                      ump_bind_backend,
                      multihop_bind_backend]
@@ -459,11 +461,36 @@ lmp_bind_backend ifn cont =
                                            C.Variable "DEFAULT_LMP_BUF_WORDS"]
     ],
     test_cb_success = C.Call "err_is_ok" [errvar],
-    test_cb_try_next = C.Binary C.Equals (C.Call "err_no" [errvar])
-                                         (C.Variable "MON_ERR_IDC_BIND_NOT_SAME_CORE"),
+    test_cb_try_next = C.Binary C.Or
+                        (C.Binary C.Equals (C.Call "err_no" [errvar]) (C.Variable "MON_ERR_IDC_BIND_NOT_SAME_CORE"))
+                        (C.Binary C.Equals (C.Call "err_no" [errvar]) (C.Variable "MON_ERR_IDC_BIND_LOCAL")),
     cleanup_bind = [ C.Ex $ C.Call "free" [binding] ]
     }
 
+local_bind_backend ifn (C.Variable cont) =
+  BindBackend {
+    flounder_backend = "local",
+    start_bind = [
+        C.If (C.Binary C.Equals (C.Call "err_no" [errvar]) (C.Variable "MON_ERR_IDC_BIND_LOCAL"))
+        [
+            C.Ex $ C.Assignment binding $ C.Call "malloc" [C.SizeOfT $ C.Struct $ intf_bind_type ifn],
+            C.Ex $ C.Call "assert" [C.Binary C.NotEquals binding (C.Variable "NULL")],
+            localvar (C.Ptr $ C.Struct "idc_export") "e" $ Nothing,
+            localvar (C.Ptr $ C.Void) "ret_binding" $ Nothing,
+            C.Ex $ C.Assignment errvar $ C.Call "idc_get_service" [iref, C.AddressOf $ C.Variable "e"],
+            C.Ex $ C.CallInd (C.DerefField (C.Variable "e") "local_connect_callback") [C.Variable "e", binding, C.AddressOf $ C.Variable "ret_binding"],
+            C.Ex $ C.Call (local_init_fn_name ifn) [binding, waitset, C.Variable "ret_binding"],
+            C.Ex $ C.Call cont [C.Variable "b", C.Variable "SYS_ERR_OK", binding]
+        ] [
+            C.Ex $ C.Call cont [C.Variable "b", errvar, C.Variable "NULL"],
+            C.Ex $ C.Assignment errvar (C.Variable "SYS_ERR_OK")
+        ]
+    ],
+    test_cb_success = C.Call "err_is_ok" [errvar],
+    test_cb_try_next = C.Variable "true",
+    cleanup_bind = []
+    }
+
 ump_bind_backend ifn cont =
   BindBackend {
     flounder_backend = "ump",
index 4ba01c3..d146e6b 100644 (file)
@@ -382,7 +382,8 @@ binding_struct n ml = C.StructDecl (intf_bind_type n) fields
         C.Param (C.TypeName "uint32_t") "outgoing_token",
         C.Param (C.Struct "thread_mutex") "rxtx_mutex",
         C.Param (C.Struct "thread_mutex") "send_mutex",
-        C.Param (C.TypeName "errval_t") "error"
+        C.Param (C.TypeName "errval_t") "error",
+        C.Param (C.Ptr $ C.Struct $ intf_bind_type n) "local_binding"
         ]
 
 --
@@ -574,7 +575,7 @@ tx_wrapper ifn (Message _ mn args _)
 -- Include the right files for different backends
 --
 
-flounder_backends = [ "lmp", "ump", "ump_ipi", "multihop" ]
+flounder_backends = [ "lmp", "ump", "ump_ipi", "multihop", "local" ]
 
 backend_includes :: String -> [ C.Unit ]
 backend_includes n =
index 6ddd4fa..5e8437c 100644 (file)
@@ -233,7 +233,7 @@ lmp_init_fn ifn = C.FunctionDef C.NoScope C.Void (lmp_init_fn_name ifn) params [
     C.Ex $ C.Assignment (common_field "get_receiving_chanstate") (C.Variable $ get_receiving_chanstate_fn_name ifn),
     C.Ex $ C.Assignment
             (C.DerefField lmp_bind_var "flags")
-            (C.Variable "LMP_SEND_FLAGS_DEFAULT") ]
+            (C.Variable "LMP_SEND_FLAGS_DEFAULT")]
     where
       params = [C.Param (C.Ptr $ C.Struct (lmp_bind_type ifn)) lmp_bind_var_name,
                 C.Param (C.Ptr $ C.Struct "waitset") "waitset"]
diff --git a/tools/flounder/Local.hs b/tools/flounder/Local.hs
new file mode 100644 (file)
index 0000000..028ae1b
--- /dev/null
@@ -0,0 +1,251 @@
+{-
+   Local.hs: Flounder stub generator for dummy local stubs
+
+  Part of Flounder: a message passing IDL for Barrelfish
+
+  Copyright (c) 2007-2010, ETH Zurich.
+  All rights reserved.
+
+  This file is distributed under the terms in the attached LICENSE file.
+  If you do not find this file, copies can be found by writing to:
+  ETH Zurich D-INFK, Universit\"atstr. 6, CH-8092 Zurich. Attn: Systems Group.
+-}
+
+module Local where
+
+import qualified CAbsSyntax as C
+import qualified Backend
+import Syntax
+import BackendCommon hiding (can_send_fn_def, register_send_fn_def)
+
+------------------------------------------------------------------------
+-- Language mapping: C identifier names
+------------------------------------------------------------------------
+
+drvname = "local"
+
+-- Name of the init function
+local_init_fn_name n = ifscope n "local_init"
+
+-- Name of the transmit vtable
+local_vtbl_name ifn = ifscope ifn "local_tx_vtbl"
+
+-- Name of the transmit function
+tx_fn_name ifn mn = idscope ifn mn "local_send"
+
+change_waitset_fn_name ifn = ifscope ifn "local_change_waitset"
+get_receiving_chanstate_fn_name ifn = ifscope ifn "local_get_receiving_chanstate"
+    
+------------------------------------------------------------------------
+-- Language mapping: Create the header file for this interconnect driver
+------------------------------------------------------------------------
+
+header :: String -> String -> Interface -> String
+header infile outfile intf@(Interface name descr decls) =
+    unlines $ C.pp_unit $ header_file intf header_body
+    where
+        header_file :: Interface -> [C.Unit] -> C.Unit
+        header_file interface@(Interface name _ _) body =
+            let sym = "__" ++ name ++ "_LOCAL_H"
+            in C.IfNDef sym ([ C.Define sym [] "1"] ++ body) []
+
+        header_body = [
+            intf_preamble infile name descr,
+            C.Blank,
+            C.MultiComment [ "Local interconnect driver" ],
+            C.Blank,
+            local_init_function_proto name,
+            local_connect_handler_proto name
+            ]
+
+local_init_function_proto :: String -> C.Unit
+local_init_function_proto n =
+    C.GVarDecl C.Extern C.NonConst
+         (C.Function C.NoScope C.Void params) name Nothing
+    where
+      name = local_init_fn_name n
+      params = [C.Param (C.Ptr $ C.Struct (intf_bind_type n)) "local_binding",
+                C.Param (C.Ptr $ C.Struct "waitset") "waitset",
+                C.Param (C.Ptr $ C.Struct (intf_bind_type n)) "my_binding"]
+
+local_connect_handler_proto :: String -> C.Unit
+local_connect_handler_proto ifn = C.GVarDecl C.Extern C.NonConst
+    (C.Function C.NoScope (C.TypeName "errval_t") local_connect_handler_params)
+    (drv_connect_handler_name drvname ifn) Nothing
+
+local_connect_handler_params :: [C.Param]
+local_connect_handler_params
+    = [C.Param (C.Ptr $ C.Void) "st",
+       C.Param (C.Ptr $ C.Void) "local_binding",
+       C.Param (C.Ptr $ C.Ptr $ C.Void) "my_binding"]
+
+------------------------------------------------------------------------
+-- Language mapping: Create the stub (implementation) for this interconnect driver
+------------------------------------------------------------------------
+
+stub :: String -> String -> Interface -> String
+stub infile outfile intf =
+    unlines $ C.pp_unit $ local_stub_body infile intf
+
+local_stub_body :: String -> Interface -> C.Unit
+local_stub_body infile intf@(Interface ifn descr decls) = C.UnitList [
+    intf_preamble infile ifn descr,
+    C.Blank,
+    C.MultiComment [ "Generated Local stub" ],
+    C.Blank,
+
+    C.Define "_USE_XOPEN" [] "/* for strdup() */",
+    C.Include C.Standard "string.h",
+    C.Include C.Standard "barrelfish/barrelfish.h",
+    C.Include C.Standard "flounder/flounder_support.h",
+    C.Include C.Standard ("if/" ++ ifn ++ "_defs.h"),
+    C.Include C.Standard ("if/" ++ ifn ++ "_local_defs.h"),
+    C.Blank,
+
+    C.MultiComment [ "Message sender functions" ],
+    C.UnitList [ tx_fn ifn m | m <- messages ],
+    C.Blank,
+
+    C.MultiComment [ "Send vtable" ],
+    tx_vtbl ifn messages,
+
+    C.MultiComment [ "Control functions" ],
+    can_send_fn_def ifn,
+    register_send_fn_def ifn,
+    default_error_handler_fn_def drvname ifn,
+    change_waitset_fn_def ifn,
+    generic_control_fn_def drvname ifn,
+    get_receiving_chanstate_fn_def ifn,
+
+    C.MultiComment [ "Function to initialise the binding state" ],
+    local_init_fn ifn,
+
+    C.MultiComment [ "Connect callback for export" ],
+    local_connect_handler_fn ifn
+    ]
+    where
+        (types, messagedecls) = Backend.partitionTypesMessages decls
+        messages = rpcs_to_msgs messagedecls
+
+local_init_fn :: String -> C.Unit
+local_init_fn ifn
+    = C.FunctionDef C.NoScope C.Void (local_init_fn_name ifn) params [
+        C.StmtList common_init,
+        C.Ex $ C.Assignment (common_field "change_waitset")
+                                (C.Variable $ change_waitset_fn_name ifn),
+        C.Ex $ C.Assignment (common_field "control")
+                                (C.Variable $ generic_control_fn_name drvname ifn),
+        C.Ex $ C.Assignment (common_field "local_binding")
+                                (C.Variable "local_binding"),
+        C.Ex $ C.Assignment (common_field "get_receiving_chanstate")
+                    (C.Variable $ get_receiving_chanstate_fn_name ifn)
+    ]
+    where
+      params = [C.Param (C.Ptr $ C.Struct (intf_bind_type ifn)) intf_bind_var,
+                C.Param (C.Ptr $ C.Struct "waitset") "waitset",
+                C.Param (C.Ptr $ C.Struct (intf_bind_type ifn)) "local_binding"]
+      common_field f = (C.Variable intf_bind_var) `C.DerefField` f
+      common_init = binding_struct_init "local" ifn
+        (C.DerefPtr $ C.Variable intf_bind_var)
+        (C.Variable "waitset")
+        (C.Variable $ local_vtbl_name ifn)
+
+can_send_fn_def :: String -> C.Unit
+can_send_fn_def ifn =
+    C.FunctionDef C.Static (C.TypeName "bool") (can_send_fn_name drvname ifn) params [
+        C.Return $ C.Variable "true"]
+    where
+        params = [ C.Param (C.Ptr $ C.Struct $ intf_bind_type ifn) "b" ]
+
+register_send_fn_def :: String -> C.Unit
+register_send_fn_def ifn =
+    C.FunctionDef C.Static (C.TypeName "errval_t") (register_send_fn_name drvname ifn) params [
+        C.Return $ C.Variable "ERR_NOTIMP"
+    ]
+    where
+        params = [ C.Param (C.Ptr $ C.Struct $ intf_bind_type ifn) "b",
+                   C.Param (C.Ptr $ C.Struct "waitset") "ws",
+                   C.Param (C.Struct "event_closure") intf_cont_var ]
+
+change_waitset_fn_def :: String -> C.Unit
+change_waitset_fn_def ifn =
+    C.FunctionDef C.Static (C.TypeName "errval_t") (change_waitset_fn_name ifn) params [
+        C.Return $ C.Variable "ERR_NOTIMP"
+    ]
+    where
+        params = [C.Param (C.Ptr $ C.Struct $ intf_bind_type ifn) intf_bind_var,
+                  C.Param (C.Ptr $ C.Struct "waitset") "ws"]
+
+tx_fn :: String -> MessageDef -> C.Unit
+tx_fn ifn msg@(Message _ mn args _) =
+    C.FunctionDef C.Static (C.TypeName "errval_t") (tx_fn_name ifn mn) params body
+    where
+        params = [binding_param ifn, cont_param] ++ (
+                    concat [ msg_argdecl TX ifn a | a <- args ])
+        cont_param = C.Param (C.Struct "event_closure") intf_cont_var
+        body = [
+            C.SComment "call rx handler",
+            C.Ex $ C.Call "assert" [C.Binary C.NotEquals handler (C.Variable "NULL")],
+            C.Ex $ C.CallInd handler ((local_binding):(concat $ map mkvars args)),
+            C.SBlank,
+            C.SComment "run continuation, if any",
+            C.If (C.Binary C.NotEquals
+                                (C.Variable intf_cont_var `C.FieldOf` "handler")
+                                (C.Variable "NULL"))
+                [C.Ex $ C.CallInd (C.Variable intf_cont_var `C.FieldOf` "handler")
+                                [C.Variable intf_cont_var `C.FieldOf` "arg"]] [],
+            C.SBlank,
+            C.Return $ C.Variable "SYS_ERR_OK"
+            ]
+        -- string and array arguments need special treatment
+        mkvars (Arg _ (StringArray n l)) = [C.Variable n]
+        mkvars (Arg _ (DynamicArray n l _)) = [C.Variable n, C.Variable l]
+        mkvars (Arg _ (Name n)) = [C.Variable n]
+
+        binding = C.Variable intf_bind_var
+        local_binding = C.DerefField binding "local_binding"
+        handler = C.FieldOf (C.DerefField local_binding "rx_vtbl") mn
+
+tx_vtbl :: String -> [MessageDef] -> C.Unit
+tx_vtbl ifn ml =
+    C.StructDef C.Static (intf_vtbl_type ifn TX) (local_vtbl_name ifn) fields
+    where
+        fields = [let mn = msg_name m in (mn, tx_fn_name ifn mn) | m <- ml]
+
+local_connect_handler_fn :: String -> C.Unit
+local_connect_handler_fn ifn = C.FunctionDef C.NoScope (C.TypeName "errval_t")
+    (drv_connect_handler_name "local" ifn) local_connect_handler_params [
+    
+    localvar (C.Ptr $ C.Struct $ export_type ifn) "e" $ Just $ C.Variable "st",
+    localvar (C.TypeName "errval_t") "err" Nothing,
+    C.SBlank,
+    C.SComment "allocate storage for binding",
+    localvar (C.Ptr $ C.Struct $ intf_bind_type ifn) intf_bind_var
+        $ Just $ C.Call "malloc" [C.SizeOfT $ C.Struct $ intf_bind_type ifn],
+    C.If (C.Binary C.Equals (C.Variable intf_bind_var) (C.Variable "NULL"))
+        [C.Return $ C.Variable "LIB_ERR_MALLOC_FAIL"] [],
+    C.SBlank,
+
+    C.Ex $ C.Call (local_init_fn_name ifn) [binding,
+        C.DerefField (C.Cast (C.Ptr $ C.Struct $ intf_bind_type ifn) (C.Variable "local_binding")) "waitset",
+        C.Variable "local_binding"],
+    C.SComment "run user's connect handler",
+    C.Ex $ C.Call "assert" [(C.DerefField exportvar "connect_cb")],
+    C.Ex $ C.Assignment errvar $ C.CallInd (C.DerefField exportvar "connect_cb")
+                       [C.DerefField exportvar "st", bindvar],
+    C.If (C.Call "err_is_fail" [errvar])
+        [C.SComment "connection refused",
+         C.Return $ errvar] [],
+    C.SBlank,
+    C.Ex $ C.Assignment (C.DerefPtr $ C.Variable "my_binding") binding,
+    C.Return $ C.Variable "SYS_ERR_OK"]
+    where
+        exportvar = C.Variable "e"
+        binding = C.Variable intf_bind_var
+
+get_receiving_chanstate_fn_def :: String -> C.Unit
+get_receiving_chanstate_fn_def ifn =
+    C.FunctionDef C.Static (C.Ptr $ C.Struct "waitset_chanstate") (get_receiving_chanstate_fn_name ifn) params [
+        C.Return $ C.Variable "NULL"]
+    where
+        params = [C.Param (C.Ptr $ C.Struct $ intf_bind_type ifn) intf_bind_var]
index dcc3940..b70bb0a 100644 (file)
@@ -36,6 +36,7 @@
 > import qualified UMP_IPI
 > import qualified Multihop
 > import qualified Loopback
+> import qualified Local
 > import qualified RPCClient
 > import qualified MsgBuf
 > import qualified THCBackend
@@ -55,6 +56,8 @@
 >            | Multihop_Header
 >            | Loopback_Header
 >            | Loopback_Stub
+>            | Local_Header
+>            | Local_Stub
 >            | RPCClient_Header
 >            | RPCClient_Stub
 >            | MsgBuf_Header
 >     where arch = optArch opts
 > generator _ Loopback_Header = Loopback.header
 > generator _ Loopback_Stub = Loopback.stub
+> generator _ Local_Header = Local.header
+> generator _ Local_Stub = Local.stub
 > generator _ RPCClient_Header = RPCClient.header
 > generator _ RPCClient_Stub = RPCClient.stub
 > generator _ MsgBuf_Header = MsgBuf.header
 >             Option [] ["multihop-stub"] (NoArg $ addTarget Multihop_Stub)     "Create a stub file for Multihop",
 >             Option [] ["loopback-header"] (NoArg $ addTarget Loopback_Header) "Create a header file for loopback",
 >             Option [] ["loopback-stub"] (NoArg $ addTarget Loopback_Stub) "Create a stub file for loopback",
+>             Option [] ["local-header"] (NoArg $ addTarget Local_Header) "Create a header file for local",
+>             Option [] ["local-stub"] (NoArg $ addTarget Local_Stub) "Create a stub file for local",
 >             Option [] ["rpcclient-header"] (NoArg $ addTarget RPCClient_Header) "Create a header file for RPC",
 >             Option [] ["rpcclient-stub"] (NoArg $ addTarget RPCClient_Stub) "Create a stub file for RPC",
 >             Option [] ["msgbuf-header"] (NoArg $ addTarget MsgBuf_Header) "Create a header file for message buffers",
index eceeccc..e90b909 100644 (file)
@@ -32,9 +32,11 @@ rpc_bind_var = "_rpc" :: String
 
 -- Name of the RPC function
 rpc_fn_name ifn mn = idscope ifn mn "rpc"
+local_rpc_fn_name ifn mn = idscope ifn mn "local_rpc"
 
 -- Name of the RPC vtable
 rpc_vtbl_name ifn = ifscope ifn "rpc_vtbl"
+local_rpc_vtbl_name ifn = ifscope ifn "local_rpc_vtbl"
 
 -- Name of the init function
 rpc_init_fn_name :: String -> String
@@ -47,6 +49,8 @@ rpc_error_fn_name ifn = ifscope ifn "rpc_client_error"
 -- Name of the struct type for the method vtable
 rpc_vtbl_type :: String -> String
 rpc_vtbl_type ifn = ifscope ifn "rpc_vtbl"
+local_rpc_vtbl_type :: String -> String
+local_rpc_vtbl_type ifn = ifscope ifn "local_rpc_vtbl"
 
 ------------------------------------------------------------------------
 -- Language mapping: Create the header file for this interconnect driver
@@ -131,10 +135,12 @@ rpc_stub_body infile intf@(Interface ifn descr decls) = C.UnitList [
 
     C.MultiComment [ "RPC wrapper functions" ],
     C.UnitList [ rpc_fn ifn types m | m <- rpcs ],
+    C.UnitList [ local_rpc_fn ifn types m | m <- rpcs ],
     C.Blank,
 
     C.MultiComment [ "RPC Vtable" ],
     rpc_vtbl ifn rpcs,
+    local_rpc_vtbl ifn rpcs,
     C.Blank,
 
 
@@ -219,12 +225,38 @@ rpc_fn ifn typedefs msg@(RPC n args _) =
             ] []
 
 
+local_rpc_fn :: String -> [TypeDef] -> MessageDef -> C.Unit
+local_rpc_fn ifn typedefs msg@(RPC n args _) =
+    C.FunctionDef C.Static (C.TypeName "errval_t") (local_rpc_fn_name ifn n) params [
+        C.Return $ C.CallInd tx_func (localbindvar:(map C.Variable $ concat $ map mkargs rpc_args))
+    ]
+    where
+        params = [rpc_binding_param ifn]
+                 ++ concat [rpc_argdecl2 TX ifn typedefs a | a <- args]
+        rpc_args = map rpc_arg args
+        tx_func = C.DerefField localbindvar "rpc_rx_vtbl" `C.FieldOf` (rpc_call_name n)
+        rpcvar = C.Variable rpc_bind_var
+        bindvar = C.DerefField rpcvar "b"
+        localbindvar = C.DerefField bindvar "local_binding"
+        rpc_arg (RPCArgIn t v) = Arg t v
+        rpc_arg (RPCArgOut t v) = Arg t v
+        mkargs (Arg _ (Name an)) = [an]
+        mkargs (Arg _ (StringArray an _)) = [an]
+        mkargs (Arg _ (DynamicArray an al _)) = [an, al]
+        (txargs, rxargs) = partition_rpc_args args
+
 rpc_vtbl :: String -> [MessageDef] -> C.Unit
 rpc_vtbl ifn ml =
     C.StructDef C.Static (rpc_vtbl_type ifn) (rpc_vtbl_name ifn) fields
     where
         fields = [let mn = msg_name m in (mn, rpc_fn_name ifn mn) | m <- ml]
 
+local_rpc_vtbl :: String -> [MessageDef] -> C.Unit
+local_rpc_vtbl ifn ml =
+    C.StructDef C.Static (rpc_vtbl_type ifn) (local_rpc_vtbl_name ifn) fields
+    where
+        fields = [let mn = msg_name m in (mn, local_rpc_fn_name ifn mn) | m <- ml]
+
 
 arg_names :: MessageArgument -> [String]
 arg_names (Arg _ v) = var_names v
@@ -256,7 +288,11 @@ rpc_init_fn ifn ml = C.FunctionDef C.NoScope (C.TypeName "errval_t")
      C.SBlank,
      C.SComment "Setup state of RPC client object",
      C.Ex $ C.Assignment (C.DerefField rpcvar "b") bindvar,
-     C.Ex $ C.Assignment (C.DerefField rpcvar "vtbl") (C.Variable $ rpc_vtbl_name ifn),
+     C.If (C.DerefField bindvar "local_binding") [
+        C.Ex $ C.Assignment (C.DerefField rpcvar "vtbl") (C.Variable $ local_rpc_vtbl_name ifn)
+     ][
+        C.Ex $ C.Assignment (C.DerefField rpcvar "vtbl") (C.Variable $ rpc_vtbl_name ifn)
+     ],
      C.Ex $ C.Assignment (C.DerefField bindvar "st") rpcvar,
      C.SBlank,
      C.SComment "Set RX handlers on binding object for RPCs",
index 8622213..ec7724f 100644 (file)
@@ -144,6 +144,83 @@ static void alloc_iref_request(struct monitor_binding *b,
     alloc_iref_reply_cont(b, service_id, iref, reterr);
 }
 
+
+static void get_service_id_reply_handler(struct monitor_binding *b,
+                                         struct monitor_msg_queue_elem *e);
+
+struct get_service_id_reply_state {
+    struct monitor_msg_queue_elem elem;
+    struct monitor_get_service_id_reply__tx_args args;
+    struct monitor_binding *b;
+};
+
+static void get_service_id_reply_cont(struct monitor_binding *b, errval_t reterr,
+                                      iref_t iref, uintptr_t service_id)
+{
+    errval_t err;
+
+    err = b->tx_vtbl.get_service_id_reply(b, NOP_CONT, reterr, iref, service_id);
+    if (err_is_fail(err)) {
+        if(err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+            struct get_service_id_reply_state *me =
+                malloc(sizeof(struct get_service_id_reply_state));
+            assert(me != NULL);
+            struct monitor_state *ist = b->st;
+            assert(ist != NULL);
+            me->args.err = reterr;
+            me->args.iref = iref;
+            me->args.service_id = service_id;
+            me->b = b;
+            me->elem.cont = get_service_id_reply_handler;
+
+            err = monitor_enqueue_send(b, &ist->queue,
+                                       get_default_waitset(), &me->elem.queue);
+            if (err_is_fail(err)) {
+                USER_PANIC_ERR(err, "monitor_enqueue_send failed");
+            }
+            return;
+        }
+
+        USER_PANIC_ERR(err, "reply failed");
+    }
+}
+
+static void get_service_id_reply_handler(struct monitor_binding *b,
+                                       struct monitor_msg_queue_elem *e)
+{
+    struct get_service_id_reply_state *st = (struct get_service_id_reply_state *)e;
+    get_service_id_reply_cont(b, st->args.err, st->args.iref, st->args.service_id);
+    free(e);
+}
+
+static void get_service_id_request(struct monitor_binding *b, iref_t iref)
+{
+    errval_t err;
+    struct monitor_binding *serv_binding = NULL;
+
+    /* Look up core_id from the iref */
+    uint8_t core_id;
+    iref_get_core_id(iref, &core_id);
+    
+    // Return error if service on different core
+    if (core_id != my_core_id) {
+        get_service_id_reply_cont(b, MON_ERR_IDC_BIND_NOT_SAME_CORE, iref, 0);
+        return;
+    }
+
+    /* Lookup the server's connection to monitor */
+    err = iref_get_binding(iref, &serv_binding);
+    if (err_is_fail(err)) {
+        get_service_id_reply_cont(b, err, iref, 0);
+        return;
+    }
+
+    /* Lookup the server's service_id */
+    uintptr_t service_id;
+    err = iref_get_service_id(iref, &service_id);
+    get_service_id_reply_cont(b, err, iref, service_id);
+}
+
 /******* stack-ripped bind_lmp_service_request *******/
 
 static void bind_lmp_client_request_error_handler(struct monitor_binding *b,
@@ -319,6 +396,12 @@ static void bind_lmp_client_request(struct monitor_binding *b,
         return;
     }
 
+    /* Check for intra-domain connection */
+    if (b == serv_binding) {
+        bind_lmp_client_request_error(b, MON_ERR_IDC_BIND_LOCAL, domain_id, serv_binding, ep);
+        return;
+    }
+
     /* Allocate a new monitor connection */
     uintptr_t con_id;
     struct lmp_conn_state *conn;
@@ -809,6 +892,7 @@ static void migrate_dispatcher_request(struct monitor_binding *b,
 
 struct monitor_rx_vtbl the_table = {
     .alloc_iref_request = alloc_iref_request,
+    .get_service_id_request = get_service_id_request,
 
     .bind_lmp_client_request= bind_lmp_client_request,
     .bind_lmp_reply_monitor = bind_lmp_reply,