Patch for using fnord on MMUless machines

Erich Schubert <[email protected]> Thu, 23 Sep 2004 14:21:54 +0200
Newsgroups gmane.comp.web.fnord
Message-ID <[email protected]>
--Q68bSM7Ycu6FN28Q
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi,
i'm running fnord on a MMUless ARM machine. Attached is a patch
modifying fnord to
* use vfork() instead of fork()
* allocate less memory on the stack and more on the heap (mmuless
  machines often have a fixed stack)
* fork as late as possible (to avoid vfork errors)

It should work the same on machines with MMU, i don't know about the
performance impacts of my changes. Using the stack might be cheaper, and
it certainly is nicer code without that extra free() at the end...

Greetings,
Erich Schubert
-- 
    erich@(vitavonni.de|debian.org)    --    GPG Key ID: 4B3A135C    (o_
  A polar bear is a rectangular bear after a coordinate transform.   //\
            Es ist besser, geliebt und verloren zu haben,            V_/_
                    als niemals geliebt zu haben.

--Q68bSM7Ycu6FN28Q
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="fnord-nommu-vfork.patch"

# * Avoid allocating large chunks on the stack
# * Fork as late as possible
# * use vfork - mmuless machines don't have fork()
# Erich Schubert <[email protected]>
diff -Nru fnord-1.8/httpd.c /home/eschubert/firm/uClinux/apps-gpl/fnord/httpd.c
--- fnord-1.8/httpd.c	2004-09-23 14:05:02.000000000 +0200
+++ fnord/httpd.c	2004-08-05 15:52:52.000000000 +0200
@@ -254,14 +254,15 @@
   return i;
 }
 
-static void do_cgi(const char* pathinfo,const char* const* envp) {
+static int do_cgi(const char* pathinfo,const char* const* envp, int fd0, int fd1, int df0, int df1) {
   const char *method_name[]={ "?", "GET", "HEAD", "POST"};
-  char cgi_env_buf[MAXHEADERLEN*2+PATH_MAX+200];
+  char *cgi_env_buf = malloc(MAXHEADERLEN*2+PATH_MAX+200);
   register unsigned int en=elen(envp);
+  int pid;
   char *tmp=cgi_env_buf;
   char **cgi_arg;
   register int i;
-  char **cgi_env=(char **)alloca((CGIENVLEN+en+1)*sizeof(char *)) ;
+  char **cgi_env=(char **)malloc((CGIENVLEN+en+1)*sizeof(char *)) ;
 
   cgi_env[0]="GATEWAY_INTERFACE=CGI/1.1";
   cgi_env[1]="SERVER_PROTOCOL=HTTP/1.0";
@@ -389,7 +390,7 @@
   if (args && (args[str_chr(args,'=')]==0)) {
     int n=3;
     for (i=0;args[i];++i) if (args[i]=='+') ++n;
-    cgi_arg=alloca(n*sizeof(char*));
+    cgi_arg=malloc(n*sizeof(char*));
     cgi_arg[n=1]=args;
     for (i=0;args[i];++i) {
       if (args[i]=='+') {
@@ -400,7 +401,7 @@
     }
     cgi_arg[++n]=0;
   } else {
-    cgi_arg=alloca(2*sizeof(char*));
+    cgi_arg=malloc(2*sizeof(char*));
     cgi_arg[1]=0;
   }
 
@@ -410,8 +411,25 @@
   tmp[str_copy(tmp+1,url)+1]=0;
 
   /* start cgi */
-  execve(cgi_arg[0],cgi_arg,cgi_env);
-  raise(SIGQUIT);	/* gateway unavailable. */
+  if (!(pid=vfork())) {
+    close(df1);
+    close(fd0);
+
+    dup2(df0,0);
+    dup2(fd1,1);
+
+    close(df0);
+    close(fd1);
+
+    alarm(CGI_TIMEOUT);
+    execve(cgi_arg[0],cgi_arg,cgi_env);
+    raise(SIGQUIT);	/* gateway unavailable. */
+  }
+  /* clean up cgi_arg, cgi_env */
+  free(cgi_env_buf);
+  free(cgi_env);
+  if (cgi_arg) free(cgi_arg);
+  return pid;
 }
 
 static void cgi_child(int sig) {
@@ -457,7 +475,7 @@
     badrequest(500,"Internal Server Error","Server Resource problem.");
   }
 
-  if ((pid=fork())) {
+  if ( (pid=do_cgi(pathinfo,envp,fd[0],fd[1],df[0],df[1])) ) {
     if (pid>0) {
       struct pollfd pfd[2];
       int nr=1;
@@ -555,19 +573,6 @@
 #endif
     }
   }
-  else {
-    close(df[1]);
-    close(fd[0]);
-
-    dup2(df[0],0);
-    dup2(fd[1],1);
-
-    close(df[0]);
-    close(fd[1]);
-
-    alarm(CGI_TIMEOUT);
-    do_cgi(pathinfo,envp);
-  }
   exit(0);
 }
 #endif
@@ -977,7 +982,7 @@
   while (testurl[0]=='/') ++testurl,--ol;
   ul=str_len(testurl);
   if (str_diff(testurl+ol,"index.html")) return 0; /* no request for index.html */
-  test=alloca(ul+1);
+  test=malloc(ul+1);
   ++test;
   ul-=4;
   byte_copy(test,ul,testurl);
@@ -1334,7 +1339,7 @@
     int i;
     host=header(buf,len,"Host");
     if (!host) i=100; else i=str_len(host)+7;
-    Buf=alloca(i);
+    Buf=malloc(i);
     if (!host) {
       char *ip=getenv("TCPLOCALIP");
       if (!ip) ip="127.0.0.1";
@@ -1391,6 +1396,7 @@
 	badrequest(404,"Not Found","<title>Not Found</title>This host is not served here.");
       }
     }
+    free(Buf);
   }
 #ifdef AUTH
   {
@@ -1402,15 +1408,15 @@
       const char *authorization;
 
       authorization = header(buf, len, "Authorization");
-      child = fork();
-      if(child < 0) {
-	badrequest(500, "Internal Server Error", "Server Resource problem.");
-      } else if(child == 0) {
+      child = vfork();
+      if(child == 0) {
 	const char *argv[5] = { auth_script, host, url, authorization, NULL };
 
 	dup2(2, 1);
 	execve(auth_script, argv, envp);
 	_exit(1);
+      } else if(child < 0) {
+	badrequest(500, "Internal Server Error", "Server Resource problem.");
       } else {
 	int status;
 	pid_t childr;

--Q68bSM7Ycu6FN28Q--