change python config, add jupyter and ein
This commit is contained in:
322
lisp/zmq/src/emacs-zmq.c
Normal file
322
lisp/zmq/src/emacs-zmq.c
Normal file
@@ -0,0 +1,322 @@
|
||||
#include "emacs-zmq.h"
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
int plugin_is_GPL_compatible;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
void *fun;
|
||||
char const * doc;
|
||||
ptrdiff_t minarity;
|
||||
ptrdiff_t maxarity;
|
||||
} ezmq_fun_t;
|
||||
|
||||
emacs_env *env = NULL;
|
||||
emacs_value Qzmq_error, Qt, Qnil, Qnth, Qlist,
|
||||
Qwrong_type_argument, Qargs_out_of_range,
|
||||
Qcons, Qstring, Qvector, Qcar, Qcdr, Qlength, Qinteger, Qequal,
|
||||
Qzmq_POLLIN, Qzmq_POLLPRI, Qzmq_POLLERR, Qzmq_POLLOUT,
|
||||
Izmq_POLLIN, Izmq_POLLPRI, Izmq_POLLERR, Izmq_POLLOUT;
|
||||
|
||||
EZMQ_DOC(ezmq_cleanup_globrefs, "",
|
||||
"Free global references flagged for release.\n"
|
||||
"Internally, ZMQ keeps references to Emacs objects that are still in use.\n"
|
||||
"Most notably, a `zmq-poller' object keeps track of all the sockets added to it\n"
|
||||
"so that they do not get cleaned up by garbage collection if they go out of scope\n"
|
||||
"while a poller is still using them.");
|
||||
static emacs_value
|
||||
ezmq_cleanup_globrefs()
|
||||
{
|
||||
emacs_value val;
|
||||
while((val = ezmq_pop_globref())) {
|
||||
FREE_GLOBREF(val);
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
#define EZMQ_MAXARGS 5
|
||||
|
||||
static emacs_value _fargs[EZMQ_MAXARGS];
|
||||
|
||||
/**
|
||||
Dispatch to the intended C function from a call to a ZMQ function in Emacs.
|
||||
|
||||
CURRENT_ENV is the current Emacs environment for the dispatch call. NARGS is
|
||||
the number of arguments for this call whose values are contained in ARGS.
|
||||
INFO is the ezmq_fun_t* which holds the function to dispatch to.
|
||||
*/
|
||||
static emacs_value
|
||||
ezmq_dispatch(emacs_env *current_env, ptrdiff_t nargs, emacs_value args[], void *info)
|
||||
{
|
||||
// Set the global environment for this dispatch call.
|
||||
env = current_env;
|
||||
|
||||
// Ensure the number of arguments are within range
|
||||
emacs_value ret = Qnil;
|
||||
if(nargs > EZMQ_MAXARGS) {
|
||||
// Better error
|
||||
ezmq_signal(Qargs_out_of_range, 2, INT(nargs), INT(EZMQ_MAXARGS));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Extract the function information
|
||||
void *fun = ((ezmq_fun_t *)info)->fun;
|
||||
ptrdiff_t maxargs = ((ezmq_fun_t *)info)->maxarity;
|
||||
|
||||
if(nargs < maxargs) {
|
||||
// Fill in nil values for optional arguments
|
||||
int i;
|
||||
for(i = (maxargs - 1); i >= nargs; i--) {
|
||||
_fargs[i] = Qnil;
|
||||
}
|
||||
for(i = 0; i < nargs; i++) {
|
||||
_fargs[i] = args[i];
|
||||
}
|
||||
args = _fargs;
|
||||
nargs = maxargs;
|
||||
}
|
||||
|
||||
// Dispatch based on number of arguments
|
||||
switch(nargs) {
|
||||
case 0:
|
||||
ret = ((emacs_value(*)(void))fun)();
|
||||
break;
|
||||
case 1:
|
||||
ret = ((emacs_value(*)(emacs_value))fun)(args[0]);
|
||||
break;
|
||||
case 2:
|
||||
ret = ((emacs_value(*)(emacs_value, emacs_value))fun)(args[0], args[1]);
|
||||
break;
|
||||
case 3:
|
||||
ret = ((emacs_value(*)(emacs_value, emacs_value,
|
||||
emacs_value))fun)(args[0], args[1],
|
||||
args[2]);
|
||||
break;
|
||||
// Currently unused
|
||||
case 4:
|
||||
ret = ((emacs_value(*)(emacs_value, emacs_value,
|
||||
emacs_value, emacs_value))fun)(args[0], args[1],
|
||||
args[2], args[3]);
|
||||
break;
|
||||
case EZMQ_MAXARGS:
|
||||
ret = ((emacs_value(*)(emacs_value, emacs_value,
|
||||
emacs_value, emacs_value,
|
||||
emacs_value))fun)(args[0], args[1],
|
||||
args[2], args[3],
|
||||
args[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
// Cleanup global references flagged for deletion
|
||||
ezmq_cleanup_globrefs();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
ezmq_bind_function(ezmq_fun_t *fun)
|
||||
{
|
||||
// Make a copy of the function information. Used by ezmq_dispatch.
|
||||
ezmq_fun_t *info = ezmq_malloc(sizeof(ezmq_fun_t));
|
||||
if(NONLOCAL_EXIT()) return;
|
||||
|
||||
memcpy(info, fun, sizeof(ezmq_fun_t));
|
||||
emacs_value Sfun = env->make_function(env,
|
||||
fun->minarity, fun->maxarity,
|
||||
&ezmq_dispatch,
|
||||
fun->doc,
|
||||
info);
|
||||
// Use defalias here so that at least we get a link to zmq.el when examining
|
||||
// the documentation for a zmq function.
|
||||
FUNCALL(INTERN("defalias"), 2, ((emacs_value []){INTERN(fun->name), Sfun}));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ezmq_provide(const char *feature)
|
||||
{
|
||||
FUNCALL(INTERN("provide"), 1, ((emacs_value []){ INTERN(feature) }));
|
||||
}
|
||||
|
||||
#define EZMQ_DEFERR(err) \
|
||||
args[0] = INTERN("zmq-"#err); \
|
||||
args[1] = STRING(#err, sizeof(#err) - 1); \
|
||||
FUNCALL(Qdefine_error, 3, args) \
|
||||
|
||||
/**
|
||||
Make error symbols for common C errors used by ZMQ. Each error symbol is the
|
||||
C error with a zmq- prefix. So EAGAIN becomes zmq-EAGAIN in Emacs.
|
||||
*/
|
||||
static void
|
||||
ezmq_make_error_symbols()
|
||||
{
|
||||
emacs_value Qdefine_error = INTERN("define-error");
|
||||
const char *msg = "An error occured in ZMQ";
|
||||
emacs_value args[3];
|
||||
|
||||
// Define the root error symbol for ZMQ errors
|
||||
args[0] = Qzmq_error;
|
||||
args[1] = STRING(msg, strlen(msg));
|
||||
args[2] = INTERN("error");
|
||||
FUNCALL(Qdefine_error, 3, args);
|
||||
|
||||
// Set zmq-ERROR as the root error for all errors defined below
|
||||
args[2] = Qzmq_error;
|
||||
// Define common errors as symbols
|
||||
// Also see zmq_signal_error
|
||||
EZMQ_DEFERR(EINVAL);
|
||||
EZMQ_DEFERR(EPROTONOSUPPORT);
|
||||
EZMQ_DEFERR(ENOCOMPATPROTO);
|
||||
EZMQ_DEFERR(EADDRINUSE);
|
||||
EZMQ_DEFERR(EADDRNOTAVAIL);
|
||||
EZMQ_DEFERR(ENODEV);
|
||||
EZMQ_DEFERR(ETERM);
|
||||
EZMQ_DEFERR(ENOTSOCK);
|
||||
EZMQ_DEFERR(EMTHREAD);
|
||||
EZMQ_DEFERR(EFAULT);
|
||||
EZMQ_DEFERR(EINTR);
|
||||
EZMQ_DEFERR(ENOTSUP);
|
||||
EZMQ_DEFERR(ENOENT);
|
||||
EZMQ_DEFERR(ENOMEM);
|
||||
EZMQ_DEFERR(EAGAIN);
|
||||
EZMQ_DEFERR(EFSM);
|
||||
EZMQ_DEFERR(EHOSTUNREACH);
|
||||
EZMQ_DEFERR(EMFILE);
|
||||
}
|
||||
|
||||
#define EZMQ_DEFUN(ename, cfun, argmin, argmax) \
|
||||
do { \
|
||||
_info.name = ename; \
|
||||
_info.fun = cfun; \
|
||||
_info.minarity = argmin; \
|
||||
_info.maxarity = argmax; \
|
||||
_info.doc = __zmq_doc_##cfun; \
|
||||
ezmq_bind_function(&_info); \
|
||||
} while (0)
|
||||
|
||||
static void
|
||||
ezmq_define_functions()
|
||||
{
|
||||
ezmq_fun_t _info;
|
||||
|
||||
// Define garbage collection functions for freeing global references
|
||||
EZMQ_DEFUN("zmq--cleanup-globrefs", ezmq_cleanup_globrefs, 0, 0);
|
||||
EZMQ_DEFUN("zmq-socket", ezmq_socket, 2, 2);
|
||||
EZMQ_DEFUN("zmq-send", ezmq_send, 2, 3);
|
||||
EZMQ_DEFUN("zmq-recv", ezmq_recv, 1, 3);
|
||||
EZMQ_DEFUN("zmq-bind", ezmq_bind, 2, 2);
|
||||
EZMQ_DEFUN("zmq-connect", ezmq_connect, 2, 2);
|
||||
EZMQ_DEFUN("zmq-join", ezmq_join, 2, 2);
|
||||
EZMQ_DEFUN("zmq-unbind", ezmq_unbind, 2, 2);
|
||||
EZMQ_DEFUN("zmq-disconnect", ezmq_disconnect, 2, 2);
|
||||
EZMQ_DEFUN("zmq-leave", ezmq_leave, 2, 2);
|
||||
EZMQ_DEFUN("zmq-close", ezmq_close, 1, 1);
|
||||
EZMQ_DEFUN("zmq-proxy", ezmq_proxy, 2, 3);
|
||||
EZMQ_DEFUN("zmq-proxy-steerable", ezmq_proxy_steerable, 2, 4);
|
||||
EZMQ_DEFUN("zmq-socket-monitor", ezmq_socket_monitor, 3, 3);
|
||||
EZMQ_DEFUN("zmq-socket-set", ezmq_setsockopt, 3, 3);
|
||||
EZMQ_DEFUN("zmq-socket-get", ezmq_getsockopt, 2, 2);
|
||||
EZMQ_DEFUN("zmq-context", ezmq_context, 0, 0);
|
||||
EZMQ_DEFUN("zmq-context-terminate", ezmq_ctx_term, 1, 1);
|
||||
EZMQ_DEFUN("zmq-context-shutdown", ezmq_ctx_shutdown, 1, 1);
|
||||
EZMQ_DEFUN("zmq-context-get", ezmq_ctx_get, 2, 2);
|
||||
EZMQ_DEFUN("zmq-context-set", ezmq_ctx_set, 3, 3);
|
||||
EZMQ_DEFUN("zmq-message", ezmq_message, 0, 1);
|
||||
EZMQ_DEFUN("zmq-message-size", ezmq_message_size, 1, 1);
|
||||
EZMQ_DEFUN("zmq-message-data", ezmq_message_data, 1, 1);
|
||||
EZMQ_DEFUN("zmq-message-more-p", ezmq_message_more, 1, 1);
|
||||
EZMQ_DEFUN("zmq-message-copy", ezmq_message_copy, 1, 1);
|
||||
EZMQ_DEFUN("zmq-message-move", ezmq_message_move, 2, 2);
|
||||
EZMQ_DEFUN("zmq-message-close", ezmq_message_close, 1, 1);
|
||||
EZMQ_DEFUN("zmq-message-set", ezmq_message_set, 3, 3);
|
||||
EZMQ_DEFUN("zmq-message-get", ezmq_message_get, 2, 2);
|
||||
EZMQ_DEFUN("zmq-message-recv", ezmq_message_recv, 2, 3);
|
||||
EZMQ_DEFUN("zmq-message-send", ezmq_message_send, 2, 3);
|
||||
EZMQ_DEFUN("zmq-message-gets", ezmq_message_gets, 2, 2);
|
||||
EZMQ_DEFUN("zmq-message-routing-id", ezmq_message_routing_id, 1, 1);
|
||||
EZMQ_DEFUN("zmq-message-set-routing-id", ezmq_message_set_routing_id, 2, 2);
|
||||
EZMQ_DEFUN("zmq-message-group", ezmq_message_group, 1, 1);
|
||||
EZMQ_DEFUN("zmq-message-set-group", ezmq_message_set_group, 2, 2);
|
||||
EZMQ_DEFUN("zmq-poll", ezmq_poll, 2, 2);
|
||||
EZMQ_DEFUN("zmq-poller", ezmq_poller_new, 0, 0);
|
||||
EZMQ_DEFUN("zmq-poller-add", ezmq_poller_add, 3, 3);
|
||||
EZMQ_DEFUN("zmq-poller-modify", ezmq_poller_modify, 3, 3);
|
||||
EZMQ_DEFUN("zmq-poller-remove", ezmq_poller_remove, 2, 2);
|
||||
EZMQ_DEFUN("zmq-poller-destroy", ezmq_poller_destroy, 1, 1);
|
||||
EZMQ_DEFUN("zmq-poller-wait", ezmq_poller_wait, 2, 2);
|
||||
EZMQ_DEFUN("zmq-poller-wait-all", ezmq_poller_wait_all, 3, 3);
|
||||
EZMQ_DEFUN("zmq-version", ezmq_version, 0, 0);
|
||||
EZMQ_DEFUN("zmq-has", ezmq_has, 1, 1);
|
||||
EZMQ_DEFUN("zmq-z85-decode", ezmq_z85_decode, 1, 1);
|
||||
EZMQ_DEFUN("zmq-z85-encode", ezmq_z85_encode, 1, 1);
|
||||
EZMQ_DEFUN("zmq-curve-keypair", ezmq_curve_keypair, 0, 0);
|
||||
EZMQ_DEFUN("zmq-curve-public", ezmq_curve_public, 1, 1);
|
||||
EZMQ_DEFUN("zmq-equal", ezmq_equal, 2, 2);
|
||||
EZMQ_DEFUN("zmq-message-p", ezmq_message_p, 1, 1);
|
||||
EZMQ_DEFUN("zmq-socket-p", ezmq_socket_p, 1, 1);
|
||||
EZMQ_DEFUN("zmq-context-p", ezmq_context_p, 1, 1);
|
||||
EZMQ_DEFUN("zmq-poller-p", ezmq_poller_p, 1, 1);
|
||||
}
|
||||
|
||||
static bool initialized = false;
|
||||
|
||||
int
|
||||
emacs_module_init(struct emacs_runtime *ert)
|
||||
{
|
||||
if(initialized)
|
||||
return 0;
|
||||
|
||||
// From https://phst.eu/emacs-modules
|
||||
/* Fail if Emacs is too old. */
|
||||
assert (ert->size > 0);
|
||||
if ((size_t) ert->size < sizeof *ert)
|
||||
return 1;
|
||||
|
||||
// Retrieve the current emacs environment
|
||||
env = ert->get_environment(ert);
|
||||
|
||||
// From https://phst.eu/emacs-modules
|
||||
if ((size_t) env->size < sizeof *env)
|
||||
return 2;
|
||||
/* Prevent Emacs’s dangerous stack overflow recovery. */
|
||||
if (signal (SIGSEGV, SIG_DFL) == SIG_ERR)
|
||||
return 3;
|
||||
|
||||
Qt = GLOBREF(INTERN("t"));
|
||||
Qnil = GLOBREF(INTERN("nil"));
|
||||
Qnth = GLOBREF(INTERN("nth"));
|
||||
Qwrong_type_argument = GLOBREF(INTERN("wrong-type-argument"));
|
||||
Qargs_out_of_range = GLOBREF(INTERN("args-out-of-range"));
|
||||
Qlist = GLOBREF(INTERN("list"));
|
||||
Qstring = GLOBREF(INTERN("string"));
|
||||
Qvector = GLOBREF(INTERN("vector"));
|
||||
Qcons = GLOBREF(INTERN("cons"));
|
||||
Qcar = GLOBREF(INTERN("car"));
|
||||
Qcdr = GLOBREF(INTERN("cdr"));
|
||||
Qequal = GLOBREF(INTERN("equal"));
|
||||
Qinteger = GLOBREF(INTERN("integer"));
|
||||
Qlength = GLOBREF(INTERN("length"));
|
||||
Qzmq_error = GLOBREF(INTERN("zmq-ERROR"));
|
||||
|
||||
ezmq_make_error_symbols();
|
||||
|
||||
ezmq_expose_constants();
|
||||
Qzmq_POLLIN = GLOBREF(INTERN("zmq-POLLIN"));
|
||||
Qzmq_POLLPRI = GLOBREF(INTERN("zmq-POLLPRI"));
|
||||
Qzmq_POLLOUT = GLOBREF(INTERN("zmq-POLLOUT"));
|
||||
Qzmq_POLLERR = GLOBREF(INTERN("zmq-POLLERR"));
|
||||
|
||||
emacs_value Qsval = INTERN("symbol-value");
|
||||
Izmq_POLLIN = GLOBREF(FUNCALL(Qsval, 1, &Qzmq_POLLIN));
|
||||
Izmq_POLLPRI = GLOBREF(FUNCALL(Qsval, 1, &Qzmq_POLLPRI));
|
||||
Izmq_POLLOUT = GLOBREF(FUNCALL(Qsval, 1, &Qzmq_POLLOUT));
|
||||
Izmq_POLLERR = GLOBREF(FUNCALL(Qsval, 1, &Qzmq_POLLERR));
|
||||
|
||||
ezmq_define_functions();
|
||||
|
||||
ezmq_provide("zmq-core");
|
||||
|
||||
if(!NONLOCAL_EXIT()) initialized = true;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user