diff --git a/.gitignore b/.gitignore
index 2c5b305..8436229 100644
--- a/.gitignore
+++ b/.gitignore
@@ -78,6 +78,7 @@ test/http/*.diff
test/http/*.err
test/http/*.out
test/http/*.ret
+test/httpd/*.bin
test/ikc3/.ikc3_history
test/ikc3/.gdb_history
test/ikc3/*.diff
diff --git a/libkc3/cfn.c b/libkc3/cfn.c
index 1587651..9556417 100644
--- a/libkc3/cfn.c
+++ b/libkc3/cfn.c
@@ -198,6 +198,24 @@ void cfn_delete (s_cfn *cfn)
free(cfn);
}
+bool cfn_eval (s_cfn *cfn)
+{
+ assert(cfn);
+ mutex_lock(&cfn->mutex);
+ if (! cfn->ready) {
+ if (! cfn_prep_cif(cfn))
+ goto ko;
+ if (! cfn_link(cfn))
+ goto ko;
+ cfn->ready = true;
+ }
+ mutex_unlock(&cfn->mutex);
+ return true;
+ ko:
+ mutex_unlock(&cfn->mutex);
+ return false;
+}
+
s_cfn * cfn_init (s_cfn *cfn, const s_sym *name, s_list *arg_types,
const s_sym *result_type)
{
@@ -269,6 +287,7 @@ s_cfn * cfn_init_copy (s_cfn *cfn, const s_cfn *src)
tmp.ptr = src->ptr;
tmp.macro = src->macro;
tmp.special_operator = src->special_operator;
+ mutex_init(&tmp.mutex);
*cfn = tmp;
return cfn;
}
@@ -282,6 +301,7 @@ s_cfn * cfn_link (s_cfn *cfn)
err_write_1(": ");
err_puts(dlerror());
assert(! "cfn_link: dlsym failed");
+ mutex_unlock(&cfn->mutex);
return NULL;
}
return cfn;
@@ -306,7 +326,10 @@ s_cfn * cfn_prep_cif (s_cfn *cfn)
ffi_type *result_ffi_type;
ffi_status status;
assert(cfn);
- mutex_lock(&cfn->mutex);
+ if (cfn->ready) {
+ result = cfn;
+ goto clean;
+ }
if (! sym_to_ffi_type(cfn->result_type, NULL, &result_ffi_type))
goto clean;
if (cfn->arity) {
@@ -323,7 +346,8 @@ s_cfn * cfn_prep_cif (s_cfn *cfn)
free(arg_ffi_type);
goto clean;
}
- if (! sym_to_ffi_type(a->tag.data.sym, result_ffi_type, arg_ffi_type + i)) {
+ if (! sym_to_ffi_type(a->tag.data.sym, result_ffi_type,
+ arg_ffi_type + i)) {
free(arg_ffi_type);
goto clean;
}
@@ -353,9 +377,9 @@ s_cfn * cfn_prep_cif (s_cfn *cfn)
assert(! "cfn_prep_cif: ffi_prep_cif: error");
goto clean;
}
+ cfn->ready = true;
result = cfn;
clean:
- mutex_unlock(&cfn->mutex);
return result;
}
diff --git a/libkc3/cfn.h b/libkc3/cfn.h
index 7d537e2..2b40b60 100644
--- a/libkc3/cfn.h
+++ b/libkc3/cfn.h
@@ -27,11 +27,12 @@ s_cfn * cfn_init_copy (s_cfn *cfn, const s_cfn *src);
void cfn_delete (s_cfn *cfn);
s_cfn * cfn_new_copy (const s_cfn *src);
-/* Observers */
+/* Observers. */
s_tag * cfn_apply (s_cfn *cfn, s_list *args, s_tag *dest);
s8 cfn_arity (const s_cfn *cfn);
-/* Modifiers */
+/* Operators. */
+bool cfn_eval (s_cfn *cfn);
s_cfn * cfn_link (s_cfn *cfn);
s_cfn * cfn_prep_cif (s_cfn *cfn);
diff --git a/libkc3/env.c b/libkc3/env.c
index 810d9ca..c6005f6 100644
--- a/libkc3/env.c
+++ b/libkc3/env.c
@@ -908,13 +908,8 @@ bool env_eval_callable (s_env *env, s_callable *callable,
case CALLABLE_CFN:
if (! (tmp = callable_new_ref(callable)))
return false;
- if (! tmp->data.cfn.ready) {
- if (! cfn_prep_cif(&tmp->data.cfn))
- goto ko;
- if (! cfn_link(&tmp->data.cfn))
- goto ko;
- tmp->data.cfn.ready = true;
- }
+ if (! cfn_eval(&tmp->data.cfn))
+ return false;
goto ok;
case CALLABLE_FN:
if (! (tmp = callable_new_copy(callable)))
diff --git a/test/httpd/Makefile b/test/httpd/Makefile
index 89a0655..554f008 100644
--- a/test/httpd/Makefile
+++ b/test/httpd/Makefile
@@ -19,4 +19,9 @@ debug: assets
run: assets
${SRC_TOP}/httpd/.libs/kc3_httpd -C ${SRC_TOP}/test/httpd 127.0.0.1 15004
+VEGETA_RATE = 10
+
+vegeta:
+ vegeta attack -rate=${VEGETA_RATE} -duration=20s < vegeta-targets.txt | tee vegeta-result.rate\=${VEGETA_RATE}.bin | vegeta plot > vegeta-result.rate\=${VEGETA_RATE}.html
+
.PHONY: assets asan cov debug main run
diff --git a/test/httpd/vegeta-targets.txt b/test/httpd/vegeta-targets.txt
new file mode 100644
index 0000000..f1f23a6
--- /dev/null
+++ b/test/httpd/vegeta-targets.txt
@@ -0,0 +1,9 @@
+GET http://127.0.0.1:15004/
+GET http://127.0.0.1:15004/test.txt
+GET http://127.0.0.1:15004/test.html
+GET http://127.0.0.1:15004/release
+GET http://127.0.0.1:15004/release/
+GET http://127.0.0.1:15004/doc
+GET http://127.0.0.1:15004/doc/
+GET http://127.0.0.1:15004/doc/1_KC3
+GET http://127.0.0.1:15004/doc/1_KC3/