4302d58260676725227d8d966c43ec6c3fc0363b
[barrelfish] / tools / sockeye / SockeyeCodeBackend.hs
1 {- 
2    GCBackend: Flounder stub generator for generic code
3    
4   Part of Flounder: a message passing IDL for Barrelfish
5    
6   Copyright (c) 2007-2010, ETH Zurich.
7   All rights reserved.
8   
9   This file is distributed under the terms in the attached LICENSE file.
10   If you do not find this file, copies can be found by writing to:
11   ETH Zurich D-INFK, Universit\"atstr. 6, CH-8092 Zurich. Attn: Systems Group.
12 -}  
13
14 module SockeyeCodeBackend where
15
16 import Data.Char
17
18
19
20 import Data.List
21 import Data.Char
22
23 import qualified CAbsSyntax as C
24 import SockeyeSyntax
25
26
27 import qualified Backend
28 import BackendCommon
29
30 include_header_name n = "facts/" ++ ifscope n "schema.h"
31
32 add_fn_name n = ifscope n "add" 
33
34
35 ------------------------------------------------------------------------
36 -- Language mapping: Create the generic header file for the interface
37 ------------------------------------------------------------------------
38
39 compile :: String -> String -> Schema -> String
40 compile infile outfile schema = 
41     unlines $ C.pp_unit $ sockeye_code_file infile schema
42
43
44 sockeye_code_file :: String -> Schema -> C.Unit
45 sockeye_code_file infile (Schema name descr decls) = 
46       let
47         (types, facts, queries) = Backend.partitionTypesFactsQueries decls
48         --messages = rpcs_to_msgs messagedecls
49     in
50       C.UnitList [
51       schema_preamble infile name descr,
52       C.Blank,
53
54       C.Include C.Standard "barrelfish/barrelfish.h",
55       C.Include C.Standard "flounder/flounder_support.h",
56       C.Include C.Standard ("schema/" ++ name ++ ".h"),
57       C.Blank,
58
59       C.MultiComment [ "Fact type signatures" ],
60       C.Blank,
61       C.UnitList [ fact_fn name f | f <- facts ],
62       C.Blank,
63
64       C.MultiComment [ "Query type signatures" ],
65       C.Blank,
66       C.UnitList [ query_fn name q | q <- queries ],
67       C.Blank
68     ]
69     
70   
71
72 --
73 -- Generate type definitions for each fact signature
74 --
75   
76 fact_fn :: String -> FactDef -> C.Unit
77 fact_fn sname f = C.UnitList [ 
78     C.MultiDoxy (["@brief  " ++ desc,
79                   ""] ++ param_desc),
80     C.FunctionDef C.NoScope (C.TypeName "errval_t") name params [
81       C.VarDecl C.NoScope C.NonConst (C.TypeName "errval_t") "err" Nothing,
82       C.SBlank,
83       C.Ex $ C.Assignment errvar (C.Call "skb_client_connect" []),
84       C.If (C.Call "err_is_fail" [errvar]) 
85         [C.Return $ errvar] [],
86       C.SBlank,
87       C.Ex $ C.Assignment errvar (C.Call "skb_add_fact" [C.Variable add_fact_string, (C.Call add_fact_args [C.Variable "arg"])]),
88       C.Return $ errvar
89     ],
90     C.Blank
91   ]
92   where 
93     name = fact_sig_type sname "add" f 
94     desc = fact_desc f 
95     params = [C.Param (C.Ptr $ C.Struct $ (fact_attrib_type sname f)) "arg"]
96     param_desc = [ fact_param_desc a | a <- fact_args f ]  
97     payload = case f of
98         Fact _ _ args -> [ fact_argdecl sname a | a <- args ]
99     add_fact_string = type_c_define sname (fact_name f) "FMT_READ"
100     add_fact_args = type_c_define sname (fact_name f) "FIELDS"
101
102
103
104 query_fn :: String -> QueryDef -> C.Unit
105 query_fn sname q = 
106   C.FunctionDecl C.NoScope (C.TypeName "errval_t") name params 
107   where 
108     name = query_sig_type sname q
109     params = concat payload
110     payload = case q of
111         Query _ _ args -> [ query_argdecl sname a | a <- args ]
112
113
114
115
116 fact_attributes :: String -> FactDef -> C.Unit
117 fact_attributes sname f = C.UnitList [ 
118     C.MultiDoxy (["Fact: " ++ name, 
119                   "@brief  " ++ desc]),
120     C.StructDecl name params,
121     C.TypeDef (C.Struct name) (name ++ "_t"),
122     C.Blank
123   ]
124   where 
125     name = fact_attrib_type sname f
126     desc = fact_desc f 
127     params = concat payload
128     payload = case f of
129         Fact _ _ args -> [ fact_attrib_decl sname a | a <- args ]
130
131
132
133
134 {-
135
136 --
137 -- Generate a struct to hold the arguments of a message while it's being sent.
138 -- 
139 msg_argstruct :: String -> [TypeDef] -> MessageDef -> C.Unit
140 msg_argstruct ifname typedefs m@(RPC n args _) = 
141     C.StructDecl (msg_argstruct_name ifname n) 
142          (concat [ rpc_argdecl ifname a | a <- args ])
143 msg_argstruct ifname typedefs m@(Message _ n [] _) = C.NoOp
144 msg_argstruct ifname typedefs m@(Message _ n args _) =
145     let tn = msg_argstruct_name ifname n
146     in
147       C.StructDecl tn (concat [ msg_argstructdecl ifname typedefs a
148                                | a <- args ])
149
150 --
151 -- Generate a union of all the above
152 -- 
153 intf_union :: String -> [MessageDef] -> C.Unit
154 intf_union ifn msgs = 
155     C.UnionDecl (binding_arg_union_type ifn)
156          ([ C.Param (C.Struct $ msg_argstruct_name ifn n) n
157             | m@(Message _ n a _) <- msgs, 0 /= length a ]
158           ++
159           [ C.Param (C.Struct $ msg_argstruct_name ifn n) n
160             | m@(RPC n a _) <- msgs, 0 /= length a ]
161          )
162
163 --
164 -- Generate a struct defn for a vtable for the interface
165 --
166 intf_vtbl :: String -> Direction -> [MessageDef] -> C.Unit
167 intf_vtbl n d ml = 
168     C.StructDecl (intf_vtbl_type n d) [ intf_vtbl_param n m d | m <- ml ]
169
170 intf_vtbl_param :: String -> MessageDef -> Direction ->  C.Param
171 intf_vtbl_param ifn m d = C.Param (C.Ptr $ C.TypeName $ msg_sig_type ifn m d) (msg_name m)
172
173 --
174 -----------------------------------------------------------------
175 -- Code to generate concrete type definitions
176 -----------------------------------------------------------------
177
178 -}
179
180 define_types :: String -> [TypeDef] -> [C.Unit]
181 define_types schemaName types = 
182     [ define_type schemaName t | t <- types ]
183
184 define_type :: String -> TypeDef -> C.Unit
185 define_type sname (TAliasT newType originType) =
186     C.TypeDef (type_c_type sname $ Builtin originType) (type_c_name1 sname newType)
187
188 {-
189 This enumeration:
190 \begin{verbatim}
191 typedef enum {
192     foo, bar, baz
193 } some_enum;
194 \end{verbatim}
195
196 Generates the following code:
197 \begin{verbatim}
198 enum ifname_some_enum_t {
199     ifname_some_enum_t_foo = 1,
200     ifname_some_enum_t_bar = 2,
201     ifname_some_enum_t_baz = 3,
202 }
203 \end{verbatim}
204 -}
205
206
207 define_type sname (TEnum name elements) = 
208     C.EnumDecl (type_c_name1 sname name) 
209          [ C.EnumItem (type_c_enum sname e) Nothing | e <- elements ]
210
211
212    
213
214 {-
215 A typedef'd alias:
216 \begin{verbatim}
217 typedef uint32 alias_type;
218 \end{verbatim}
219
220 Should compile to:
221 \begin{verbatim}
222 typedef uint32_t ifname_alias_type_t;
223 \end{verbatim}
224 -}
225
226 define_type sname (TAlias newType originType) = 
227     C.TypeDef (type_c_type sname originType) (type_c_name1 sname newType)
228
229
230 {-
231 import GHBackend (flounder_backends, export_fn_name, bind_fn_name, accept_fn_name, connect_fn_name)
232 import BackendCommon
233
234
235
236
237 -- name of the bind continuation function
238 bind_cont_name :: String -> String
239 bind_cont_name ifn = ifscope ifn "bind_continuation_direct"
240
241 -- name of an alternative bind continuation function
242 bind_cont_name2 :: String -> String
243 bind_cont_name2 ifn = ifscope ifn "bind_contination_multihop"
244
245
246
247 compile :: String -> String -> Interface -> String
248 compile infile outfile interface = 
249     unlines $ C.pp_unit $ stub_body infile interface
250
251 stub_body :: String -> Interface -> C.Unit
252 stub_body infile (Interface ifn descr _) = C.UnitList [
253     intf_preamble infile ifn descr,
254     C.Blank,
255
256     C.Include C.Standard "barrelfish/barrelfish.h",
257     C.Include C.Standard "flounder/flounder_support.h",
258     C.Include C.Standard ("if/" ++ ifn ++ "_defs.h"),
259     C.Blank,
260
261     C.MultiComment [ "Export function" ],
262     export_fn_def ifn,
263     C.Blank,
264
265     C.MultiComment [ "Functions to accept/connect over a already shared frame" ],
266     accept_fn_def ifn,
267     C.Blank,
268
269     C.MultiComment [ "Generic bind function" ],
270     -- the two bind functions use the idc drivers in a different order
271     bind_cont_def ifn (bind_cont_name ifn) (bind_backends ifn (bind_cont_name ifn)),
272     bind_cont_def ifn (bind_cont_name2 ifn) (multihop_bind_backends ifn (bind_cont_name2 ifn)),
273     bind_fn_def ifn,
274     connect_fn_def ifn]
275
276
277 export_fn_def :: String -> C.Unit
278 export_fn_def n = 
279     C.FunctionDef C.NoScope (C.TypeName "errval_t") (export_fn_name n) params [
280         localvar (C.Ptr $ C.Struct $ export_type n) "e"
281             (Just $ C.Call "malloc" [C.SizeOfT $ C.Struct $ export_type n]),
282         C.If (C.Binary C.Equals exportvar (C.Variable "NULL"))
283             [C.Return $ C.Variable "LIB_ERR_MALLOC_FAIL"] [],
284         C.SBlank,
285         C.SComment "fill in common parts of export struct",
286         C.StmtList [C.Ex $ C.Assignment dste (C.Variable srcn) | (dste, srcn) <- [
287                         (exportvar `C.DerefField` "connect_cb", "connect_cb"),
288                         (exportvar `C.DerefField` "waitset", "ws"),
289                         (exportvar `C.DerefField` "st", "st"),
290                         (commonvar `C.FieldOf` "export_callback", "export_cb"),
291                         (commonvar `C.FieldOf` "flags", "flags"),
292                         (commonvar `C.FieldOf` "connect_cb_st", "e"),
293                         (commonvar `C.FieldOf` "export_cb_st", "st")]],
294         C.SBlank,
295         C.SComment "fill in connect handler for each enabled backend",
296         C.StmtList [
297             C.SIfDef ("CONFIG_FLOUNDER_BACKEND_" ++ (map toUpper drv))
298              [C.Ex $ C.Assignment
299                         (commonvar `C.FieldOf` (drv_connect_callback drv))
300                         (C.Variable $ drv_connect_handler_name drv n)] []
301             | drv <- flounder_backends ],
302         C.SBlank,
303
304         C.Return $ C.Call "idc_export_service" [C.AddressOf commonvar]
305     ]
306     where 
307         params = [ C.Param (C.Ptr $ C.TypeName "void") "st",
308                    C.Param (C.Ptr $ C.TypeName "idc_export_callback_fn") "export_cb",
309                    C.Param (C.Ptr $ C.TypeName $ connect_callback_name n) "connect_cb",
310                    C.Param (C.Ptr $ C.Struct "waitset") "ws",
311                    C.Param (C.TypeName "idc_export_flags_t") "flags"]
312         exportvar = C.Variable "e"
313         commonvar = exportvar `C.DerefField` "common"
314
315         -- XXX: UMP_IPI uses the UMP connect callback
316         drv_connect_callback "ump_ipi" = drv_connect_callback "ump"
317         drv_connect_callback drv = drv ++ "_connect_callback"
318
319 accept_fn_def :: String -> C.Unit
320 accept_fn_def n = 
321     C.FunctionDef C.NoScope (C.TypeName "errval_t") (accept_fn_name n) params [
322         C.StmtList [
323         -- #ifdef CONFIG_FLOUNDER_BACKEND_UMP
324         C.SIfDef "CONFIG_FLOUNDER_BACKEND_UMP" [
325             C.Return $ C.Call (drv_accept_fn_name "ump" n)
326                 [ C.Variable intf_frameinfo_var,
327                   C.Variable "st",
328                   C.Variable intf_cont_var,
329                   C.Variable "ws",
330                   C.Variable "flags"]
331              ]
332              -- #else
333             [ C.StmtList [
334                  C.Ex $ C.Call "assert" [
335                      C.Unary C.Not $ C.StringConstant "UMP backend not enabled!"
336                  ],
337                  C.Return $ C.Variable "ERR_NOTIMP"
338               ]
339             ]
340         ]
341     ]
342     where 
343         params = [ C.Param (C.Ptr $ C.Struct $ intf_frameinfo_type n) intf_frameinfo_var,
344                    C.Param (C.Ptr $ C.TypeName "void") "st",
345        --          C.Param (C.Ptr $ C.TypeName "idc_export_callback_fn") "export_cb",
346                    C.Param (C.Ptr $ C.TypeName $ intf_bind_cont_type n) intf_cont_var,
347                    C.Param (C.Ptr $ C.Struct "waitset") "ws",
348                    C.Param (C.TypeName "idc_export_flags_t") "flags"]
349
350
351 connect_fn_def :: String -> C.Unit
352 connect_fn_def n = 
353     C.FunctionDef C.NoScope (C.TypeName "errval_t") (connect_fn_name n) params [
354         C.StmtList [
355         -- #ifdef CONFIG_FLOUNDER_BACKEND_UMP
356         C.SIfDef "CONFIG_FLOUNDER_BACKEND_UMP" [
357             C.Return $ C.Call (drv_connect_fn_name "ump" n)
358                 [ C.Variable intf_frameinfo_var,
359                   C.Variable intf_cont_var,
360                   C.Variable "st",
361                   C.Variable "ws",
362                   C.Variable "flags" ]
363         ]
364         -- #else
365         [ C.StmtList [
366              C.Ex $ C.Call "assert" [
367                  C.Unary C.Not $ C.StringConstant "UMP backend not enabled!"
368              ],
369              C.Return $ C.Variable "ERR_NOTIMP"
370           ]
371         ] ]
372     ]
373     where 
374         params = [ C.Param (C.Ptr $ C.Struct $ intf_frameinfo_type n) intf_frameinfo_var,
375                    C.Param (C.Ptr $ C.TypeName $ intf_bind_cont_type n) intf_cont_var,
376                    C.Param (C.Ptr $ C.TypeName "void") "st",
377                    C.Param (C.Ptr $ C.Struct "waitset") "ws",
378                    C.Param (C.TypeName "idc_bind_flags_t") "flags"]
379
380
381 -- bind continuation function
382 bind_cont_def :: String -> String -> [BindBackend] -> C.Unit
383 bind_cont_def ifn fn_name backends =
384     C.FunctionDef C.Static C.Void fn_name params [
385         C.SComment "This bind cont function uses the different backends in the following order:",
386         C.SComment $ unwords $ map flounder_backend backends,
387         C.SBlank,
388
389         localvar (C.Ptr $ C.Struct "flounder_generic_bind_attempt") "b"
390             (Just $ C.Variable "st"),
391         C.Switch driver_num cases
392             [C.Ex $ C.Call "assert" [C.Unary C.Not $ C.StringConstant "invalid state"]],
393         C.SBlank,
394         C.Label "out",
395         C.Ex $ C.CallInd (C.Cast (C.Ptr $ C.TypeName $ intf_bind_cont_type ifn)
396                                 (bindst `C.DerefField` "callback"))
397                         [bindst `C.DerefField` "st", errvar, C.Variable intf_bind_var],
398         C.Ex $ C.Call "free" [bindst]
399     ]
400     where
401         params = [ C.Param (C.Ptr $ C.Void) "st",
402                    C.Param (C.TypeName "errval_t") "err",
403                    C.Param (C.Ptr $ C.Struct $ intf_bind_type ifn) intf_bind_var]
404         driver_num = bindst `C.DerefField` "driver_num"
405         bindst = C.Variable "b"
406         cases = [ C.Case (C.NumConstant $ toInteger n) (mkcase n)
407                   | n <- [0 .. length backends] ]
408
409         mkcase n
410             | n == 0 = try_next
411
412             | n == length backends = [
413                 C.SIfDef config_prev_driver
414                     [C.If (test_cb_success prev_backend)
415                         -- success!
416                         [success_callback]
417                         -- failure, but clean up attempt
418                         [C.StmtList $ cleanup_bind prev_backend,
419                          C.If (C.Unary C.Not $ test_cb_try_next prev_backend)
420                             [fail_callback errvar]
421                             []]
422                     ]
423                     [],
424                 fail_callback (C.Variable "FLOUNDER_ERR_GENERIC_BIND_NO_MORE_DRIVERS")
425                 ]
426
427             | otherwise = [
428                 C.SIfDef config_prev_driver
429                     [C.If (test_cb_success prev_backend)
430                         -- success!
431                         [success_callback]
432
433                         -- failure, cleanup and decide whether to continue
434                         [C.StmtList $ cleanup_bind prev_backend,
435                          C.If (test_cb_try_next prev_backend)
436                             [C.Goto ("try_next_" ++ show n)]
437                             [C.SComment "report permanent failure to user",
438                              fail_callback errvar]
439                             ],
440
441                      C.Label ("try_next_" ++ show n)
442                     ] [],
443
444                 -- previous driver not enabled, just try the next
445                 C.StmtList try_next]
446             where
447                 prev_backend = backends !! (n - 1)
448                 next_backend = backends !! n
449                 config_prev_driver = "CONFIG_FLOUNDER_BACKEND_"
450                                 ++ (map toUpper (flounder_backend prev_backend))
451                 config_next_driver = "CONFIG_FLOUNDER_BACKEND_"
452                                 ++ (map toUpper (flounder_backend next_backend))
453
454                 try_next = [C.Ex $ C.PostInc driver_num,
455                             C.SIfDef config_next_driver
456                                 [C.SComment "try next backend",
457                                  C.StmtList $ start_bind next_backend,
458                                  C.If (C.Call "err_is_fail" [errvar])
459                                     -- bind attempt failed
460                                     [C.StmtList $ cleanup_bind next_backend,
461                                      fail_callback errvar]
462                                     [C.ReturnVoid]]
463                                 [C.SComment "skip non-enabled backend (fall through)"]]
464
465                 fail_callback err = C.StmtList $
466                     (if err /= errvar
467                         then [C.Ex $ C.Assignment errvar err]
468                         else [])
469                     ++ [
470                         C.Ex $ C.Assignment (C.Variable intf_bind_var) (C.Variable "NULL"),
471                         C.Goto "out"]
472
473                 success_callback = C.Goto "out"
474
475
476 bind_fn_def :: String -> C.Unit
477 bind_fn_def n = 
478     C.FunctionDef C.NoScope (C.TypeName "errval_t") (bind_fn_name n) params [
479         C.SComment "allocate state",
480         localvar (C.Ptr $ C.Struct "flounder_generic_bind_attempt") "b"
481             (Just $ C.Call "malloc" [C.SizeOfT $ C.Struct "flounder_generic_bind_attempt"]),
482         C.If (C.Binary C.Equals (C.Variable "b") (C.Variable "NULL"))
483             [C.Return $ C.Variable "LIB_ERR_MALLOC_FAIL"] [],
484         C.SBlank,
485         C.SComment "fill in binding state",
486         C.StmtList [C.Ex $ C.Assignment (C.Variable "b" `C.DerefField` dstf) srce
487                     | (dstf, srce) <- [
488                         ("iref", C.Variable "iref"),
489                         ("waitset", C.Variable "waitset"),
490                         ("driver_num", C.NumConstant 0),
491                         ("callback", C.Variable intf_cont_var),
492                         ("st", C.Variable "st"),
493                         ("flags", C.Variable "flags")]],
494         C.SBlank,
495         C.If (C.Binary C.BitwiseAnd (C.Variable "flags") (C.Variable "IDC_BIND_FLAG_MULTIHOP"))
496         [C.Ex $ C.Call (bind_cont_name2 n) [C.Variable "b", C.Variable "SYS_ERR_OK", C.Variable "NULL"]]
497         [C.Ex $ C.Call (bind_cont_name n) [C.Variable "b", C.Variable "SYS_ERR_OK", C.Variable "NULL"]],
498         C.SBlank,
499         C.Return $ C.Variable "SYS_ERR_OK"
500     ]
501     where 
502       params = [ C.Param (C.TypeName "iref_t") "iref",
503                  C.Param (C.Ptr $ C.TypeName $ intf_bind_cont_type n) intf_cont_var,
504                  C.Param (C.Ptr $ C.TypeName "void") "st",
505                  C.Param (C.Ptr $ C.Struct "waitset") "waitset",
506                  C.Param (C.TypeName "idc_bind_flags_t") "flags" ]
507
508 ----------------------------------------------------------------------------
509 -- everything that we need to know about a backend to attempt a generic bind
510 ----------------------------------------------------------------------------
511 data BindBackend = BindBackend {
512     flounder_backend :: String,     -- name of the flounder backend
513     start_bind :: [C.Stmt],         -- code to attempt a bind
514     test_cb_success :: C.Expr,      -- expression to test if a bind succeeded (in the callback)
515     test_cb_try_next :: C.Expr,     -- expression to test if a bind might succeed with another backend
516     cleanup_bind :: [C.Stmt]        -- code to cleanup a failed bind
517 }
518
519 -- the available bind backends
520 -- Cation: order of list matters (we will try to bind in that order)
521 bind_backends :: String -> String -> [BindBackend]
522 bind_backends ifn cont_fn_name = map (\i -> i ifn (C.Variable cont_fn_name)) 
523                     [lmp_bind_backend, 
524                      ump_ipi_bind_backend, 
525                      ump_bind_backend, 
526                      multihop_bind_backend]
527                                                      
528 -- backends in different order (prefer multihop over ump, etc.)
529 multihop_bind_backends :: String -> String -> [BindBackend]
530 multihop_bind_backends ifn cont_fn_name = map (\i -> i ifn (C.Variable cont_fn_name))
531                     [lmp_bind_backend, 
532                      multihop_bind_backend, 
533                      ump_ipi_bind_backend, 
534                      ump_bind_backend]
535
536 bindst = C.Variable "b"
537 binding = bindst `C.DerefField` "binding"
538 iref = bindst `C.DerefField` "iref"        
539 waitset = bindst `C.DerefField` "waitset"
540 flags = bindst `C.DerefField` "flags"
541
542 lmp_bind_backend ifn cont = 
543   BindBackend {
544     flounder_backend = "lmp",
545     start_bind = [
546         C.Ex $ C.Assignment binding $
547             C.Call "malloc" [C.SizeOfT $ C.Struct $ lmp_bind_type ifn],
548         C.Ex $ C.Call "assert" [C.Binary C.NotEquals binding (C.Variable "NULL")],
549         C.Ex $ C.Assignment errvar $
550             C.Call (lmp_bind_fn_name ifn) [binding, iref, cont, C.Variable "b", waitset,
551                                            flags,
552                                            C.Variable "DEFAULT_LMP_BUF_WORDS"]
553     ],
554     test_cb_success = C.Call "err_is_ok" [errvar],
555     test_cb_try_next = C.Binary C.Equals (C.Call "err_no" [errvar])
556                                          (C.Variable "MON_ERR_IDC_BIND_NOT_SAME_CORE"),
557     cleanup_bind = [ C.Ex $ C.Call "free" [binding] ]
558     }
559   
560 ump_bind_backend ifn cont =   
561   BindBackend {
562     flounder_backend = "ump",
563     start_bind = [
564         C.Ex $ C.Assignment binding $
565             C.Call "malloc" [C.SizeOfT $ C.Struct $ UMP.bind_type ifn],
566         C.Ex $ C.Call "assert" [C.Binary C.NotEquals binding (C.Variable "NULL")],
567         C.Ex $ C.Assignment errvar $
568             C.Call (UMP.bind_fn_name ifn) [binding, iref, cont, C.Variable "b", waitset,
569                                            flags,
570                                            C.Variable "DEFAULT_UMP_BUFLEN",
571                                            C.Variable "DEFAULT_UMP_BUFLEN"]
572     ],
573     test_cb_success = C.Call "err_is_ok" [errvar],
574     test_cb_try_next = C.Variable "true",
575     cleanup_bind = [ C.Ex $ C.Call "free" [binding] ]
576     }
577   
578 ump_ipi_bind_backend ifn cont = 
579   BindBackend {
580     flounder_backend = "ump_ipi",
581     start_bind = [
582         C.Ex $ C.Assignment binding $
583             C.Call "malloc" [C.SizeOfT $ C.Struct $ UMP_IPI.bind_type ifn],
584         C.Ex $ C.Call "assert" [C.Binary C.NotEquals binding (C.Variable "NULL")],
585         C.Ex $ C.Assignment errvar $
586             C.Call (UMP_IPI.bind_fn_name ifn) [binding, iref, cont, C.Variable "b", waitset,
587                                            flags,
588                                            C.Variable "DEFAULT_UMP_BUFLEN",
589                                            C.Variable "DEFAULT_UMP_BUFLEN"]
590     ],
591     test_cb_success = C.Call "err_is_ok" [errvar],
592     test_cb_try_next = C.Variable "true",
593     cleanup_bind = [ C.Ex $ C.Call "free" [binding] ]
594     }
595   
596 multihop_bind_backend ifn cont = 
597   BindBackend {
598     flounder_backend = "multihop",
599     start_bind = [C.Ex $ C.Assignment binding $
600                          C.Call "malloc" [C.SizeOfT $ C.Struct $ Multihop.m_bind_type ifn],
601                          C.Ex $ C.Call "assert" [C.Binary C.NotEquals binding (C.Variable "NULL")],
602                          C.Ex $ C.Assignment errvar $
603                          C.Call (Multihop.m_bind_fn_name ifn) [binding, iref, cont, C.Variable "b", waitset, flags]],
604     test_cb_success = C.Call "err_is_ok" [errvar],
605     test_cb_try_next = C.Variable "true",
606     cleanup_bind = [ C.Ex $ C.Call "free" [binding] ]
607     }
608
609 -}