extended the build system to support .o files and added preliminary gccgo plugin

This commit is contained in:
Unbit
2013-05-09 18:38:53 +02:00
parent 2374ba12bd
commit cd604ef07b
3 changed files with 240 additions and 4 deletions
+127
View File
@@ -0,0 +1,127 @@
#include <uwsgi.h>
/*
Soon before official Go 1.1, we understand supporting Go in a fork() heavy
environment was not blessed by the Go community.
Instead of completely dropping support for Go, we studied how the gccgo project works and we
decided it was a better approach for uWSGI.
This new plugin works by initializing a new "go runtime" after each fork().
The runtime calls the Go main function (developed by the user), and pass the whole
uWSGI control to it.
the uwsgi.Run() go function directly calls the uwsgi_takeover() function (it automatically
manages mules, spoolers and workers)
*/
struct uwsgi_gccgo{
struct uwsgi_string_list *libs;
} ugccgo;
struct uwsgi_option uwsgi_gccgo_options[] = {
{"go-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0},
{"gccgo-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0},
//{"goroutines", required_argument, 0, "a shortcut setting optimal options for goroutine-based apps, takes the number of goroutines to spawn as argument", uwsgi_opt_setup_goroutines, NULL, UWSGI_OPT_THREADS},
{0, 0, 0, 0, 0, 0, 0},
};
// no_split_stack is the key to avoid crashing !!!
void* runtime_m(void) __attribute__ ((noinline, no_split_stack));
void runtime_check(void);
void runtime_args(int, char **);
void runtime_osinit(void);
void runtime_schedinit(void);
void *__go_go(void *, void *);
void runtime_main(void);
void runtime_mstart(void *);
extern void uwsgigo_request(void *, void *) __asm__ ("go.uwsgi.RequestHandler");
extern void* uwsgigo_env(void *) __asm__ ("go.uwsgi.Env");
extern void* uwsgigo_env_add(void *, void *, uint16_t, void *, uint16_t) __asm__ ("go.uwsgi.EnvAdd");
static void mainstart(void *arg __attribute__((unused))) {
runtime_main();
}
void uwsgigo_main_main(void) __asm__ ("main.main");
void uwsgigo_main_init(void) __asm__ ("__go_init_main");
void (*uwsgigo_hook_init)(void);
void (*uwsgigo_hook_main)(void);
void uwsgigo_main_init(void) {
uwsgigo_hook_init();
}
void uwsgigo_main_main(void) {
uwsgigo_hook_main();
}
static void uwsgi_gccgo_initialize() {
struct uwsgi_string_list *usl = ugccgo.libs;
while(usl) {
void *handle = dlopen(usl->value, RTLD_NOW | RTLD_GLOBAL);
if (!handle) {
uwsgi_log("unable to open go shared library: %s\n", dlerror());
exit(1);
}
uwsgi_log("[uwsgi-gccgo] loaded %s\n", usl->value);
uwsgigo_hook_init = dlsym(handle, "__go_init_main");
uwsgigo_hook_main = dlsym(handle, "main.main");
usl = usl->next;
}
if (!uwsgigo_hook_init || !uwsgigo_hook_main) {
return;
}
// Go runtime initialization
char *argv[2] = {0};
runtime_check();
runtime_args(0, argv);
runtime_osinit();
runtime_schedinit();
__go_go(mainstart, NULL);
runtime_mstart(runtime_m());
// never here
}
static int uwsgi_gccgo_request(struct wsgi_request *wsgi_req) {
/* Standard GO request */
if (!wsgi_req->uh->pktsize) {
uwsgi_log("Empty GO request. skip.\n");
return -1;
}
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
wsgi_req->async_environ = uwsgigo_env(wsgi_req);
int i;
for(i=0;i<wsgi_req->var_cnt;i++) {
uwsgigo_env_add(wsgi_req->async_environ, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len);
i++;
}
uwsgigo_request(wsgi_req->async_environ, wsgi_req);
return UWSGI_OK;
}
static void uwsgi_gccgo_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
struct uwsgi_plugin gccgo_plugin = {
.name = "gccgo",
.modifier1 = 11,
.options = uwsgi_gccgo_options,
.request = uwsgi_gccgo_request,
.after_request = uwsgi_gccgo_after_request,
.post_fork = uwsgi_gccgo_initialize,
};
+107
View File
@@ -0,0 +1,107 @@
package uwsgi
import (
"strings"
"net/http"
"net/http/cgi"
)
//extern uwsgi_takeover
func uwsgi_takeover()
//extern uwsgi_response_write_body_do
func uwsgi_response_write_body_do(*interface{}, *byte, uint64) int
//extern uwsgi_response_prepare_headers_int
func uwsgi_response_prepare_headers_int(*interface{}, int) int
//extern uwsgi_response_add_header
func uwsgi_response_add_header(*interface{}, *byte, uint16, *byte, uint16) int
//extern uwsgi_request_body_read
func uwsgi_request_body_read(*interface{}, []byte, uint64) int
func Env(wsgi_req *interface{}) *map[string]string {
var env map[string]string
env = make(map[string]string)
return &env
}
func EnvAdd(env *map[string]string, k *[65536]byte, kl uint16, v *[65536]byte, vl uint16) {
(*env)[ string((*k)[0:kl]) ] = string((*v)[0:vl])
}
type ResponseWriter struct {
r *http.Request
wsgi_req *interface{}
headers http.Header
wroteHeader bool
}
func (w *ResponseWriter) Write(p []byte) (n int, err error) {
if !w.wroteHeader {
w.WriteHeader(http.StatusOK)
}
uwsgi_response_write_body_do(w.wsgi_req, &p[0], uint64(len(p)))
return len(p), err
}
func (w *ResponseWriter) WriteHeader(status int) {
uwsgi_response_prepare_headers_int(w.wsgi_req, status )
if w.headers.Get("Content-Type") == "" {
w.headers.Set("Content-Type", "text/html; charset=utf-8")
}
for k := range w.headers {
for _, v := range w.headers[k] {
v = strings.NewReplacer("\n", " ", "\r", " ").Replace(v)
v = strings.TrimSpace(v)
kb := []byte(k)
vb := []byte(v)
uwsgi_response_add_header(w.wsgi_req, &kb[0], uint16(len(k)), &vb[0], uint16(len(v)))
}
}
w.wroteHeader = true
}
func (w *ResponseWriter) Header() http.Header {
return w.headers
}
type BodyReader struct {
wsgi_req *interface{}
}
// there is no close in request body
func (br *BodyReader) Close() error {
return nil
}
func (br *BodyReader) Read(p []byte) (n int, err error) {
return 0, err
}
/*
m := len(p)
var body []byte = uwsgi_request_body_read(br.wsgi_req, C.ssize_t(m), &rlen)
if (body[0] == 0) {
err = io.EOF;
return 0, err
} else if (body != nil) {
return int(rlen), err
}
err = io.ErrUnexpectedEOF
rlen = 0
return int(rlen), err
}
*/
func RequestHandler(env *map[string]string, wsgi_req *interface{}) {
httpReq, err := cgi.RequestFromMap(*env)
if err == nil {
httpReq.Body = &BodyReader{wsgi_req}
w := ResponseWriter{httpReq, wsgi_req,http.Header{},false}
http.DefaultServeMux.ServeHTTP(&w, httpReq)
}
}
func Run() {
uwsgi_takeover()
}
+6 -4
View File
@@ -1,6 +1,6 @@
# uWSGI build system
uwsgi_version = '1.9.9'
uwsgi_version = '1.9.10'
import os
import re
@@ -153,7 +153,7 @@ def spcall3(cmd):
def add_o(x):
if x == 'uwsgi':
x = 'main'
elif x.endswith('.a'):
elif x.endswith('.a') or x.endswith('.o'):
return x
x = x + '.o'
return x
@@ -277,7 +277,7 @@ def build_uwsgi(uc, print_only=False):
objfile = file
if objfile == 'uwsgi':
objfile = 'main'
if not objfile.endswith('.a'):
if not objfile.endswith('.a') and not objfile.endswith('.o'):
compile(' '.join(cflags), last_cflags_ts, objfile + '.o', file + '.c')
if uc.get('embedded_plugins'):
@@ -346,6 +346,8 @@ def build_uwsgi(uc, print_only=False):
for cfile in up['GCC_LIST']:
if cfile.endswith('.a'):
gcc_list.append(cfile)
elif cfile.endswith('.o'):
gcc_list.append('%s/%s' % (path, cfile))
elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.m'):
compile(' '.join(uniq_warnings(p_cflags)), last_cflags_ts,
path + '/' + cfile + '.o', path + '/' + cfile + '.c')
@@ -1122,7 +1124,7 @@ def build_plugin(path, uc, cflags, ldflags, libs, name = None):
for cfile in up['GCC_LIST']:
if cfile.endswith('.a'):
gcc_list.append(cfile)
elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.m'):
elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.m') and not cfile.endswith('.o'):
gcc_list.append(path + '/' + cfile + '.c')
else:
gcc_list.append(path + '/' + cfile)