Created
October 30, 2014 18:12
-
-
Save sustrik/ca839c6813ab655eded4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Thu Oct 30 06:48:25 +0100 2014: | |
This file was generated by mill from helloserver.mc */ | |
#include <stdmill.h> | |
/* This example is a TCP server application that accepts connections and | |
sends "Hello, world!" to each of them. Afterwards it closes the connection. | |
Use telnet to connect to it: "telnet 127.0.0.1 7000". */ | |
#include <stdmill.h> | |
#include <assert.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdio.h> | |
struct connection | |
{ | |
struct tcpsocket s; | |
}; | |
/* Coframe definition for coroutine 'dialogue'. */ | |
struct mill_cf_dialogue { | |
/* Generic coframe header. */ | |
struct mill_cfh mill_cfh; | |
/* Coroutine arguments. */ | |
struct connection * conn; | |
/* Local variables. */ | |
int rc; | |
const char * hi; | |
}; | |
/* Event handler for coroutine 'dialogue'. */ | |
static int mill_handler_dialogue (void *cfptr, void *event) | |
{ | |
struct mill_cf_dialogue *cf; | |
cf = (struct mill_cf_dialogue*) cfptr; | |
/* Continue from the point where the coroutine was interrupted. */ | |
switch (cf->mill_cfh.pc) { | |
case 0: break; | |
case 1: goto mill_pc_1; | |
case 2: goto mill_pc_2; | |
case 3: goto mill_pc_3; | |
case 4: goto mill_pc_4; | |
default: assert (0); | |
} | |
mill_go_tcpsocket_send (&mill_type_tcpsocket_send, cf->mill_cfh.loop, cf, &(cf->rc), &(cf->conn)->s, (cf->hi), strlen ((cf->hi))); | |
/* Wait for next event. */ | |
cf->mill_cfh.pc = 1; | |
return 0; | |
mill_pc_1: | |
/* If child coroutine 'tcpsocket_send' have terminated. */ | |
if (mill_typeof(event) == &mill_type_tcpsocket_send) { | |
mill_coframe_term (event, 0); | |
assert ((cf->rc) == 0); | |
} | |
/* If parent coroutine have canceled this coroutine. */ | |
else if (event == NULL) { | |
goto mill_finally; | |
} | |
/* If the event can't be processed at the moment. */ | |
else return -1; | |
mill_go_tcpsocket_term (&mill_type_tcpsocket_term, cf->mill_cfh.loop, cf, &(cf->conn)->s); | |
/* Wait for next event. */ | |
cf->mill_cfh.pc = 2; | |
return 0; | |
mill_pc_2: | |
/* If child coroutine 'tcpsocket_term' have terminated. */ | |
if (mill_typeof(event) == &mill_type_tcpsocket_term) { | |
mill_coframe_term (event, 0); | |
} | |
/* If parent coroutine have canceled this coroutine. */ | |
else if (event == NULL) { | |
goto mill_finally; | |
} | |
/* If the event can't be processed at the moment. */ | |
else return -1; | |
free ((cf->conn)); | |
/* The main part of the coroutine is finished. | |
What follows is the termination-related code. */ | |
mill_finally: | |
/* Cancel any remaining child coroutines. */ | |
mill_cancel_children (cf); | |
cf->mill_cfh.pc = 3; | |
goto mill_test_children; | |
mill_pc_3: | |
mill_coframe_term (event, 1); | |
/* If there are no remaining children notify the parent that | |
the coroutine have finished. */ | |
mill_test_children: | |
if (mill_has_children (cf)) | |
return 0; | |
mill_emit (cf); | |
cf->mill_cfh.pc = 4; | |
return 0; | |
mill_pc_4: | |
/* If finished coroutine was selected | |
copy the out arguments to their final destinations. */ | |
if (event) { | |
assert (event == cf); | |
cf->mill_cfh.pc = -1; | |
return 0; | |
} | |
cf->mill_cfh.pc = -1; | |
return 0; | |
} | |
/* Metadata for coroutine 'dialogue'. */ | |
const struct mill_type mill_type_dialogue = { | |
mill_handler_dialogue, | |
"dialogue" | |
}; | |
/* Start asynchronous execution of coroutine 'dialogue'. */ | |
void mill_go_dialogue ( | |
const struct mill_type *type, | |
struct mill_loop *loop, | |
void *parent, | |
struct connection * conn) | |
{ | |
struct mill_cf_dialogue *cf; | |
/* Allocate new coframe. */ | |
cf = malloc (sizeof (struct mill_cf_dialogue)); | |
assert (cf); | |
/* Inialise the coframe. */ | |
mill_coframe_init (cf, type, parent, loop); | |
cf->conn = conn; | |
cf->hi = "Hello, world!\n"; | |
/* Execute the initial part of the coroutine. */ | |
mill_handler_dialogue (&cf->mill_cfh, 0); | |
} | |
/* Execute coroutine 'dialogue' in blocking/synchronous manner. */ | |
void dialogue ( | |
struct connection * conn) | |
{ | |
struct mill_loop loop; | |
mill_loop_init (&loop); | |
/* Execute initial part of the coroutine. */ | |
mill_go_dialogue (&mill_type_dialogue, &loop, NULL, conn); | |
/* Run the event loop until the coroutine exits. */ | |
mill_loop_run (&loop); | |
mill_loop_term (&loop); | |
} | |
/* Coframe definition for coroutine 'server'. */ | |
struct mill_cf_server { | |
/* Generic coframe header. */ | |
struct mill_cfh mill_cfh; | |
/* Local variables. */ | |
int rc; | |
struct sockaddr_in addr; | |
struct tcpsocket ls; | |
struct connection * conn; | |
}; | |
/* Event handler for coroutine 'server'. */ | |
static int mill_handler_server (void *cfptr, void *event) | |
{ | |
struct mill_cf_server *cf; | |
cf = (struct mill_cf_server*) cfptr; | |
/* Continue from the point where the coroutine was interrupted. */ | |
switch (cf->mill_cfh.pc) { | |
case 0: break; | |
case 1: goto mill_pc_1; | |
case 2: goto mill_pc_2; | |
case 3: goto mill_pc_3; | |
default: assert (0); | |
} | |
/* Open the listening socket. */ | |
(cf->rc) = uv_ip4_addr ("127.0.0.1", 7000, &(cf->addr)); | |
assert ((cf->rc) == 0); | |
(cf->rc) = tcpsocket_init (&(cf->ls)); | |
assert ((cf->rc) == 0); | |
(cf->rc) = tcpsocket_bind (&(cf->ls), (struct sockaddr*) &(cf->addr), 0); | |
assert ((cf->rc) == 0); | |
(cf->rc) = tcpsocket_listen (&(cf->ls), 10); | |
assert ((cf->rc) == 0); | |
while (1) { | |
/* Create a connection object for the new incoming connection. */ | |
(cf->conn) = malloc (sizeof (struct connection)); | |
assert ((cf->conn)); | |
(cf->rc) = tcpsocket_init (&(cf->conn)->s); | |
assert ((cf->rc) == 0); | |
mill_go_tcpsocket_accept (&mill_type_tcpsocket_accept, cf->mill_cfh.loop, cf, &(cf->rc), &(cf->conn)->s, &(cf->ls)); | |
while (1) { | |
/* Wait for next event. */ | |
cf->mill_cfh.pc = 1; | |
return 0; | |
mill_pc_1: | |
/* If child coroutine 'tcpsocket_accept' have terminated. */ | |
if (mill_typeof(event) == &mill_type_tcpsocket_accept) { | |
mill_coframe_term (event, 0); | |
assert ((cf->rc) == 0); | |
printf ("Connection opened!\n"); | |
mill_go_dialogue (&mill_type_dialogue, cf->mill_cfh.loop, cf, (cf->conn)); | |
break; | |
} | |
/* If child coroutine 'dialogue' have terminated. */ | |
else if (mill_typeof(event) == &mill_type_dialogue) { | |
mill_coframe_term (event, 0); | |
printf ("Connection closed!\n"); | |
} | |
/* If parent coroutine have canceled this coroutine. */ | |
else if (event == NULL) { | |
goto mill_finally; | |
} | |
/* If the event can't be processed at the moment. */ | |
else return -1; | |
} | |
} | |
/* The main part of the coroutine is finished. | |
What follows is the termination-related code. */ | |
mill_finally: | |
/* Cancel any remaining child coroutines. */ | |
mill_cancel_children (cf); | |
cf->mill_cfh.pc = 2; | |
goto mill_test_children; | |
mill_pc_2: | |
mill_coframe_term (event, 1); | |
/* If there are no remaining children notify the parent that | |
the coroutine have finished. */ | |
mill_test_children: | |
if (mill_has_children (cf)) | |
return 0; | |
mill_emit (cf); | |
cf->mill_cfh.pc = 3; | |
return 0; | |
mill_pc_3: | |
/* If finished coroutine was selected | |
copy the out arguments to their final destinations. */ | |
if (event) { | |
assert (event == cf); | |
cf->mill_cfh.pc = -1; | |
return 0; | |
} | |
cf->mill_cfh.pc = -1; | |
return 0; | |
} | |
/* Metadata for coroutine 'server'. */ | |
const struct mill_type mill_type_server = { | |
mill_handler_server, | |
"server" | |
}; | |
/* Start asynchronous execution of coroutine 'server'. */ | |
void mill_go_server ( | |
const struct mill_type *type, | |
struct mill_loop *loop, | |
void *parent) | |
{ | |
struct mill_cf_server *cf; | |
/* Allocate new coframe. */ | |
cf = malloc (sizeof (struct mill_cf_server)); | |
assert (cf); | |
/* Inialise the coframe. */ | |
mill_coframe_init (cf, type, parent, loop); | |
/* Execute the initial part of the coroutine. */ | |
mill_handler_server (&cf->mill_cfh, 0); | |
} | |
/* Execute coroutine 'server' in blocking/synchronous manner. */ | |
void server () | |
{ | |
struct mill_loop loop; | |
mill_loop_init (&loop); | |
/* Execute initial part of the coroutine. */ | |
mill_go_server (&mill_type_server, &loop, NULL); | |
/* Run the event loop until the coroutine exits. */ | |
mill_loop_run (&loop); | |
mill_loop_term (&loop); | |
} | |
int main () | |
{ | |
server (); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment