changeset 142:7bbdc034e347

Fix some bugs. Get basic network code working (epoll listener + accept connections). Start porting webserver.
author Mike Pavone <pavone@retrodev.com>
date Sun, 21 Nov 2010 16:33:17 -0500
parents f2cb85c53ced
children ff00538cd818
files cbackend_c.rhope ctobin kernel.rhope net.rhope nworker_c.rhope parser_old_c.rhope runtime/context.c runtime/func.h runtime/net.c webserver.rhope
diffstat 10 files changed, 389 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/cbackend_c.rhope	Sat Nov 20 17:48:22 2010 -0500
+++ b/cbackend_c.rhope	Sun Nov 21 16:33:17 2010 -0500
@@ -154,11 +154,17 @@
 					[[type]Name >>]Slice[3] {}
 					{ typename <- [["int"]Append[~]]Append["_t"] }
 				}{
-					,regulartype <- [("UInt64","UInt32","UInt16","UInt8")]Find[=[[type]Name >>,?]]
+					[("UInt64","UInt32","UInt16","UInt8")]Find[=[[type]Name >>,?]]
 					{
 						primitive <- Yes
 						[[type]Name >>]Slice[4] {}
 						{ typename <- [["uint"]Append[~]]Append["_t"] }
+					}{
+						,regulartype <- If[[[type]Name >>]=["Context"]]
+						{
+							typename <- "context *"
+							primitive <- Yes
+						}
 					}
 				}
 			}
@@ -778,6 +784,15 @@
 {
 	worker <- Make Op[Strip Addref[to call], func]
 	rargs <- Map[args, Make Op[?, func]]
+	
+	If[[[[func]Variables >>]Length]+[[[func]Outputs >>]Length]]
+	{
+		valcall <- "ValCall("
+		postlude <- "ValCallPostlude("
+	}{
+		valcall <- "ValCallNoLocals("
+		postlude <- "ValCallNoLocalsPostlude("
+	}
 
 	If[[[func]Last NumParams >>] = [-1]]
 	{
@@ -803,7 +818,7 @@
 	
 	out <- [[[[Fold[_Val Function Arg C[?, ?, ?, worker], prepped, rargs]
 	]Add Raw Line[
-		[[[[[[[["ValCall("
+		[[[[[[[[valcall
 		]Append[worker]
 		]Append[", "]
 		]Append[String[[rargs]Length]]
@@ -814,7 +829,7 @@
 		]Append[")"]]
 	]Add Raw Line["DISPATCH"]
 	]Add Raw Line[
-		[[[["ValCallPostlude("
+		[[[[postlude
 		]Append[String[[func]Resume Index >>]]
 		]Append[", "]
 		]Append[Escape Rhope Name[[func]Name >>,[func]Escape Pattern >>]]
@@ -845,10 +860,14 @@
 	}
 }
 
-Func Base@C Function[func,tocall,args,type:out]
+Func Base@C Function[func,tocall,args,rtype:out]
 {
 	Print[ [[func]Name >>]Append[ [": Func Base("]Append[tocall] ] ]
 	rargs <- Map[args, Make Op[?, func]]
+	
+	If[[[[func]Variables >>]Length]+[[[func]Outputs >>]Length]]
+	{ type <- Val[rtype] }
+	{ type <- [rtype]Append["NoLocals"] }
 
 	If[[[rargs]Length] > [[func]Last NumParams >>]]
 	{	
@@ -1131,24 +1150,25 @@
 		}
 		fname <- Escape Rhope Name[[func]Name >>,[func]Escape Pattern >>]
 		param check <- Fold[Check Param Type C[?, ?, ?, func], "", [func]Input Types >>]
+		If[[[func]Last NumParams >>] = [-1]]
+		{
+			freecall <- ""
+		}{
+			freecall <- "\n\tFreeCall\n"
+		}
 		If[ [ [[[[func]Variables >>]Length]+[[[func]Outputs >>]Length]]+[[[func]Uses >>]Length] ] = [0] ]
 		{
-			out <- [[[[[[[[ [type]Append["NoLocals("]
+			out <- [[[[[[[[[ [type]Append["NoLocals("]
 				]Append[cname]
 				]Append[",\n\tNumParams "]
 				]Append[ String[[[func]Inputs >>]Length] ]
 				]Append[")\n\n"]
 				]Append[param check]
 				]Append[ [[func]Statements >>]Join[""] ]
+				]Append[freecall]
 				]Append["EndFuncNoLocals\n"]
 				]Append["DISPATCH"]
 		}{
-			If[[[func]Last NumParams >>] = [-1]]
-			{
-				freecall <- ""
-			}{
-				freecall <- "\n\tFreeCall\n"
-			}
 			If[[[func]Uses >>]Length]
 			{
 				begin trans <- [[[["\tbegin_transaction(ct, "]Append[ String[[[func]Uses >>]Length] ]]Append[", "]]Append[ [Map[Map[[func]Uses >>, Escape Rhope Name[?, [func]Escape Pattern >>]], ["gs_"]Append[?]]]Join[", "] ]]Append[");\n"]
--- a/ctobin	Sat Nov 20 17:48:22 2010 -0500
+++ b/ctobin	Sun Nov 21 16:33:17 2010 -0500
@@ -20,8 +20,8 @@
 
 file=$1
 shift
-echo "$CC -o $bin $@ $file.c blueprint.c context.c fixed_alloc.c object.c transaction.c"
-$CC -o $bin $@ "$file.c" blueprint.c context.c fixed_alloc.c object.c transaction.c
+echo "$CC -o $bin $@ $file.c blueprint.c context.c fixed_alloc.c object.c transaction.c net.c"
+$CC -o $bin $@ "$file.c" blueprint.c context.c fixed_alloc.c object.c transaction.c net.c
 
 cd ..
 
--- a/kernel.rhope	Sat Nov 20 17:48:22 2010 -0500
+++ b/kernel.rhope	Sun Nov 21 16:33:17 2010 -0500
@@ -290,7 +290,7 @@
 _Call Async[func,cont:out]
 {
 	Resume[cont,0]
-	{ out <- Call[func] }
+	{ out <- Call[func,0] }
 }
 Call Async[func:out]
 {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/net.rhope	Sun Nov 21 16:33:17 2010 -0500
@@ -0,0 +1,253 @@
+
+Foreign C:libc
+{
+	setsockopt[sockfd(Int32,Naked),level(Int32,Naked),optname(Int32,Naked),optval(Int32,Raw Pointer),optlen(Int32,Naked):out(Int32,Naked)]
+	listen[sockfd(Int32,Naked),backlog(Int32,Naked):out(Int32,Naked)]
+	send[sockfd(Int32,Naked),data(Array,Raw Pointer),datalen(Int64,Naked):out(Int32,Naked)]
+	recv[sockfd(Int32,Naked),data(Array,Raw Pointer,Mutable),maxlen(Int64,Naked):out(Int32,Naked),data]
+	fcntl[fd(Int32,Naked),command(Int32,Naked),value(Int64,Naked):out(Int32,Naked)]
+	pipe[descriptors(Array,Raw Pointer,Mutable):out(Int32,Naked),descriptors]
+	epoll_create[size(Int32,Naked):status(Int32,Naked)]
+	epoll_ctl[epfd(Int32,Naked),operation(Int32,Naked),fd(Int32,Naked),event(epoll_event,Raw Pointer):status(Int32,Naked)]
+	epoll_wait[epfd(Int32,Naked),events(Array,Raw Pointer,Mutable),maxevents(Int32,Naked),timeout(Int32,Naked):out(Int32,Naked),events]
+}
+
+
+//Note: port numbers would more properly be UInt16, think about changing later
+Foreign C:runtime
+{
+	_internal_bindnewsocket[port(Int32,Naked),setreuse(Int32,Naked):socket(Int32,Naked)]
+	_internal_accept[sockfd(Int32,Naked),addrbuf(Array,Raw Pointer,Mutable),buflen(Int32,Naked):consock(Int32,Naked),addrbuf]
+}
+
+Blueprint epoll_event
+{
+	events(UInt32,Naked)
+	data(Int64,Naked)
+}
+
+//EPOLLIN 1
+//EPOLLOUT 4
+//EPOLLPRI 2
+//EPOLL_CTL_ADD 1
+//EPOLL_CTL_DEL 2
+//EPOLL_CTL_MOD 3
+
+_Add New FDs[epfd,pipefd:out]
+{
+	count,rdata <- read[pipefd, _internal_array_allocnaked[2,Int32()], 8i64]
+	,out <- If[[count]=[8i64]]
+	{
+		data <- [rdata]Length <<[2]
+		epoll_ctl[epfd, 1i32, [data]Index[0], [[Build[epoll_event()]]events <<[Abs UInt[[data]Index[1]]]]data <<[Int64[[data]Index[0]]]]
+		{ out <- _Add New FDs[epfd,pipefd] }
+	}{
+		//TODO: Properly deal with the case when count > 0 but < 8
+		If[[count]>[0i64]]
+		{
+			Print[["read of listener pipe returned unexpected number of bytes: "]Append[String[count]]]
+		}
+	}
+}
+
+_Get IO Context[fd:out,notfound] uses socklisten
+{
+	out,notfound <- [socklisten::fdlookup]Index[fd]
+}
+
+_Handle Events[epfd,pipefd,buf,cur:out]
+{
+	event,out <- [buf]Index[cur]
+	{
+		If[[event]data >>]
+		{
+			activefd <- Trunc Int32[[event]data >>]
+			epoll_ctl[epfd, 2, activefd, Build[epoll_event()]]
+			{	
+				If[[[event]events >>]&[8216u32]]
+				{ res <- No }
+				{ res <- Yes }
+				ct,cont <- _Get IO Context[activefd]
+				{
+				}{ Print["Could not find context for IO event"] }
+				,cont <- Resume[ct,res]
+				{
+					cont <- Yield[]
+				}{
+					Print["could not resume context for IO event"]
+				}
+			}
+		}{
+			cont <- _Add New FDs[epfd,pipefd]
+		}
+		Val[cont]
+		{
+			out <- _Handle Events[epfd,pipefd,buf,[cur]+[1]]
+		}
+	}
+}
+
+_Wait Active[epfd,pipefd,buf]
+{
+	workaround <- Yield[]
+	Val[workaround]
+	{
+		count,newbuf <- epoll_wait[epfd,buf,[buf]Storage >>,-1]
+		If[[count]=[-1]]
+		{
+			Print["epoll_wait returned error"]
+		}{
+			If[[count]=[0]]
+			{
+				//Shouldn't happen normally, but perhaps if there was a signal
+				_Wait Active[epfd,pipefd,buf]
+			}{
+				_Handle Events[epfd,pipefd,[newbuf]Length <<[count],0]
+				{ _Wait Active[epfd,pipefd,buf] }
+			}
+		}
+	}
+}
+
+_Sock Listener[pipefd]
+{
+	epfd <- epoll_create[16]
+	If[[epfd]=[-1]]
+	{
+		Print["Error creating epoll file descriptor"]
+	}{
+		If[[epoll_ctl[epfd,1i32,pipefd,[[Build[epoll_event()]]events <<[1u32]]data <<[0i64]]]=[-1]]
+		{
+			Print["Error adding pipe to epoll fd"]
+		}{
+			_Wait Active[epfd, pipefd, _internal_array_allocnaked[8,epoll_event()]]
+		}
+	}
+}
+
+Globals socklisten
+{
+	listener started <- No
+	fdlookup <- ()
+	pipefd <- -1
+}
+
+_Add FD to Listener[fd,context:pipefd,err] uses socklisten
+{
+	If[socklisten::listener started]
+	{
+		pipefd <- socklisten::pipefd
+		do add <- Yes
+	}{
+		//Calling a function with side effects inside a transaction is BAD
+		//Need to do something about this
+		ret,des <- pipe[[Array[]]Set[1, 0i32]]
+		If[[ret]=[-1]]
+		{
+			err <- "Error creating pipe for waking up socket listener"
+		}{
+			socklisten::pipefd <- [des]Index[1]
+			pipefd <- [des]Index[1]
+			//fcntl[fd, F_SETFL, O_NONBLOCK]
+			//Set both ends of the pipe to non blocking
+			fcntl[[des]Index[0], 4i32, 2048i64]
+			fcntl[[des]Index[1], 4i32, 2048i64]
+			socklisten::listener started <- Yes
+			Call Async[_Sock Listener[[des]Index[0],?]]
+			do add <- Yes
+		}
+	}
+	Val[do add]
+	{
+		socklisten::fdlookup <- [socklisten::fdlookup]Set[fd, context]
+	}
+}
+
+_Write to Listener Pipe[pipefd,data]
+{
+	res <- write[pipefd, data, 8i64]
+	If[[res]!=[8i32]]
+	{
+		workaround <- Yield[]
+		Val[workaround]
+		{ _Write to Listener Pipe[pipefd,data] }
+	}
+}
+
+_Wait for IO[fd,type,context]
+{
+	_Add FD to Listener[fd,context]
+	{
+		_Write to Listener Pipe[~,[[Array[]]Append[fd]]Append[type]]
+	}{
+		Print[~]
+		{ Resume[context,No] }
+	}
+}
+
+Wait for IO[fd,type:out]
+{
+	out <- Pause[_Wait for IO[fd,type,?]]
+}
+
+_Do Con Call[newfd,address,tocall]
+{
+	[tocall]Call[newfd,address]
+}
+
+_Null Term[raw str,cur:out]
+{
+	[raw str]Index[cur]
+	{
+		If[[~]=[0u8]]
+		{
+			out <- String[[raw str]Length <<[cur]]
+		}{
+			out <- _Null Term[raw str, [cur]+[1]]
+		}
+	}{
+		out <- String[raw str]
+	}
+}
+
+_Port Wait[fd,tocall:out]
+{
+	con <- _internal_accept[fd,_internal_array_allocnaked[40,UInt8()],40] {}
+	{ address <- _Null Term[[~]Length <<[40], 0i32] }
+	If[[con]=[-1]]
+	{
+		If[Wait for IO[fd, 1i32]]
+		{
+			out <- _Port Wait[fd,tocall]
+		}{
+			Print["Error waiting for connection"]
+		}
+	}{
+		Call Async[_Do Con Call[con,address,tocall,?]]
+		{
+			out <- _Port Wait[fd,tocall]
+		}
+	}
+}
+
+Listen on Port[port(Int32),tocall:out]
+{
+	fd <- _internal_bindnewsocket[port,1]
+	//fcntl[fd, F_SETFL, O_NONBLOCK]
+	//Set listen socket to non blocking
+	If[[fd]=[-1]]
+	{ out <- No }
+	{
+		fcntl[fd, 4i32, 2048i64]
+		{ listen[fd,8]
+		{ out <- Call Async[_Port Wait[fd,tocall,?]] }}
+	}
+}
+
+//This effectively leaks a context and thus any data on the stack of that context
+//Need either handle cleanup of contexts or find a better way to accomplish this
+Wait Forever[]
+{
+	Pause[Val[?]]
+}
+
--- a/nworker_c.rhope	Sat Nov 20 17:48:22 2010 -0500
+++ b/nworker_c.rhope	Sun Nov 21 16:33:17 2010 -0500
@@ -1069,7 +1069,7 @@
 
 Node Result Vars[vars,node,index:out]
 {
-	[("call","getfield","setfield")]Find[=[[node]Type >>, ?]]
+	[("call","getfield","setfield","getglobal")]Find[=[[node]Type >>, ?]]
 	{
 		If[[[node]Type >>]=["call"]]
 		{
--- a/parser_old_c.rhope	Sat Nov 20 17:48:22 2010 -0500
+++ b/parser_old_c.rhope	Sun Nov 21 16:33:17 2010 -0500
@@ -1056,7 +1056,8 @@
 				value,after <- Parse Number[name, params]
 			}{
 				delims <- [[[[[[[("\n")]Append[[params]Block Begin >>]]Append[[params]Block End >>]]Append[[params]Empty Block >>]]Append[[params]Arg End >>]]Append[[params]List Delim >>]]Append[[params]List End >>]]Append[[params]List Begin >>]
-				afterdelim,raw before,delim,nodelim <- [name]Get Comment DString[delims, params]
+				afterdelim,raw before,delim,nodelim <- [name]Get Comment DString[delims, params] {} {} {}
+				{ delim <- "" }
 
 				before <- Trim[raw before, "\r\n\t "]
 				If[[delim] = [[params]List Begin >>]]
@@ -1435,9 +1436,12 @@
 			}
 			Val[valstring]
 			{
+				Print[["Parsing initial value: "]Append[valstring]]
 				value <- [Named Pipe or Literal[Trim[~, "\r\n\t "], params]]Value >>
 				next store <- [store]Vars <<[ [[store]Vars >>]Set[varname, value] ]
 			}
+		}{
+			Print[["Expected assignment operator in global var block, found "]Append[trimmed]]
 		}
 	}{
 		out <- store
--- a/runtime/context.c	Sat Nov 20 17:48:22 2010 -0500
+++ b/runtime/context.c	Sun Nov 21 16:33:17 2010 -0500
@@ -34,12 +34,14 @@
 int32_t put_cqueue(context * ct)
 {
 	rh_lock(cq_lock);
-		if ((cq_writeloc+1)&31 == cq_readloc)
-		{
+		if (((cq_writeloc+1)&31) == cq_readloc)
+		{	
 			rh_unlock(cq_lock);
 			return 0;
 		}
 		contextqueue[cq_writeloc++] = ct;
+		if(cq_writeloc == 32)
+			cq_writeloc = 0;
 	rh_unlock(cq_lock);
 	return 1;
 }
--- a/runtime/func.h	Sat Nov 20 17:48:22 2010 -0500
+++ b/runtime/func.h	Sun Nov 21 16:33:17 2010 -0500
@@ -287,6 +287,24 @@
 	my_cdata = cdata->lastframe;\
 	RESUME_SELF
 
+#define CallNoLocals(tocall, numparams, resumeto, myname)\
+			cdata->func = RES_  ## resumeto ## _ ## myname;\
+			cdata->num_params = numparams;\
+			if(FUNC_ ## tocall == FUNC_ ## myname) {\
+				PAUSE_SELF\
+				AND_TOTAL\
+			} else if (FUNC_ ## tocall != FUNC_PL_ && FUNC_ ## tocall != FUNC_MN_ && FUNC_ ## tocall != FUNC_TM_ && FUNC_ ## tocall != FUNC_DV_ && FUNC_ ## tocall != FUNC_If) {\
+				PAUSE_SELF\
+			}\
+			goto sf_ ## tocall;\
+r ## resumeto ## _ ## myname:\
+			my_cdata = cdata->lastframe;\
+			if(FUNC_ ## tocall == FUNC_ ## myname) {\
+				RESUME_SELF\
+				AND_RESUME_TOTAL\
+			} else if (FUNC_ ## tocall != FUNC_PL_ && FUNC_ ## tocall != FUNC_MN_ && FUNC_ ## tocall != FUNC_TM_ && FUNC_ ## tocall != FUNC_DV_ && FUNC_ ## tocall != FUNC_If) {\
+				RESUME_SELF\
+			}
 
 #define Call(tocall, numparams, resumeto, myname)\
 			cdata->func = RES_  ## resumeto ## _ ## myname;\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/net.c	Sun Nov 21 16:33:17 2010 -0500
@@ -0,0 +1,65 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdio.h>
+
+int _internal_accept(int sockfd, char * addrbuf, int buflen)
+{
+	int retfd;
+	socklen_t addr_size;
+	struct sockaddr_storage remote_addr;
+	addr_size = sizeof(remote_addr);
+	retfd = accept(sockfd, (struct sockaddr *)&remote_addr, &addr_size);
+	if (addrbuf && buflen)
+	{
+		addrbuf[0] = '\0';
+		if(retfd == -1)
+			return retfd;
+		switch(remote_addr.ss_family)
+		{
+		case AF_INET:
+			inet_ntop(AF_INET, &(((struct sockaddr_in *)&remote_addr)->sin_addr), addrbuf, buflen);
+			break;
+		case AF_INET6:
+			inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)&remote_addr)->sin6_addr), addrbuf, buflen);
+			break;
+		}
+	}
+	return retfd;
+}
+
+
+int _internal_bindnewsocket(unsigned int port, int setreuse)
+{
+	char portstr[6];
+	int sockfd,flag=1;
+	struct addrinfo hints, *localaddr;
+	
+	snprintf(portstr, 6, "%d", port & 0XFFFF);
+	
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_flags = AI_PASSIVE;
+	
+	getaddrinfo(NULL, portstr, &hints, &localaddr);
+	
+	sockfd = socket(localaddr->ai_family, localaddr->ai_socktype, localaddr->ai_protocol);
+	if (sockfd == -1)
+	{
+		freeaddrinfo(localaddr);
+		return sockfd;
+	}
+	if(setreuse)
+		setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,&flag,sizeof(int));
+	if(-1 == bind(sockfd, localaddr->ai_addr, localaddr->ai_addrlen))
+	{
+		close(sockfd);
+		sockfd = -1;
+	}
+	freeaddrinfo(localaddr);
+	return sockfd;
+}
+
--- a/webserver.rhope	Sat Nov 20 17:48:22 2010 -0500
+++ b/webserver.rhope	Sun Nov 21 16:33:17 2010 -0500
@@ -1,4 +1,3 @@
-Import extendlib.rhope
 
 Get Content Type[path:out]
 {
@@ -42,7 +41,7 @@
 		default headers <- [start headers]Set["Content-Length", content length]
 	}
 	
-	out <- [client]Put String@Net Client[
+	out <- [client]Put String[
 				[
 					[
 						[
@@ -87,13 +86,14 @@
 			,newpath <- [path]Slice[1]
 			If[[newpath] = ["default.css"]]
 			{
-			file <- <String@File[newpath]
+			file <- Open[File[newpath],"r"]
 			content length <- Length[file]
 			If[[content length] > [0]]
 			{
-				junk,data <- [file]Get FString[content length]
+				data <- [file]Read[content length]
 				[HTTP OK[client, Get Content Type[path], content length, Dictionary[]]
-				]Put String@Net Client[data]
+				]Write[data]
+				{ Close[file] }
 			}{
 				HTTP Not Found[client]
 			}
@@ -118,12 +118,12 @@
 
 Connection Start[con,handlers]
 {
-	client, request <- [con]Get DString@Net Client["\r\n"]
-	parts <- [request]Split@String[" "]
+	client, request <- [con]Get DString["\r\n"]
+	parts <- [request]Split[" "]
 	Print[request]
-	[client]Get DString@Net Client["\r\n\r\n"]
+	[client]Get DString["\r\n\r\n"]
 	{
-		Handle Request[~, [parts]Index@List[0], [parts]Index@List[1], headers, handlers]
+		Handle Request[~, [parts]Index[0], [parts]Index[1], headers, handlers]
 	}{
 		headers <- Map[Dict Split[~, ":", "\r\n"], ["Trim"]Set Input[1, " \t"]]
 	}