Skip to content

Instantly share code, notes, and snippets.

@sustrik
Created October 30, 2014 18:12
Show Gist options
  • Save sustrik/ca839c6813ab655eded4 to your computer and use it in GitHub Desktop.
Save sustrik/ca839c6813ab655eded4 to your computer and use it in GitHub Desktop.
/* 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