[Ecls-list] cl_boot crash

Juan Jose Garcia-Ripoll juanjose.garciaripoll at googlemail.com
Sun Aug 1 14:20:57 UTC 2010


The problem you just found is intimately related to the other one. ECL
uses a garbage collector, evaluation environments and other stuff that
has to be created *for each* thread where you want to execute or
evaluate Common Lisp code. In the simple modification you made the
routine new_Command1 just evaluated a lisp form in a thread that was
simply not prepared for it.

The solution is to construct one or more Common Lisp slave threads
that are responsible for executing code and communicating the
appropriate output to the master threads, which may be dynamically
created and destroyed by the GUI library.

Below is  cut & paste of some code I tested with your application. It
works fine, except for the problem with quitting, which leaves the 4D
environment in some kind of locked status. Debugging does not offer
much information: all the active threads are from 4D and I do not have
the sources of it.

typedef struct {
	int pipe[2];
	void *message;
	int integer;
} comm_t;

void
comm_open(comm_t *c)
{
	pipe(c->pipe);
}

void
comm_close(comm_t *c)
{
	close(c->pipe[0]);
	close(c->pipe[1]);
}

void *
comm_read(comm_t *c)
{
	char b;
	printf("Reading from pipe from %x\n", (int)pthread_self());
	if (read(c->pipe[0], &b, sizeof(b)) < 0 || b != 0x13)
		return NULL;
	return c->message;
}

void
comm_write(comm_t *c, void *message)
{
	static const char b[1] = { 0x13 };
	c->message = message;
	printf("Writing to pipe from %x\n", (int)pthread_self());
	write(c->pipe[1], b, sizeof(*b));
}

int
comm_read_int(comm_t *c)
{
	comm_read(c);
	return c->integer;
}

void
comm_write_int(comm_t *c, int i)
{
	c->integer = i;
	comm_write(c, &c->integer);
}

#define EMBED_ECL
#ifdef EMBED_ECL

static pthread_t ecl_thread;
static comm_t slave_pipe[1];
static comm_t master_pipe[1];

static void *
ecl_thread_entry(void *aux)
{
	int argc = 1;
    char * argv[256];
	cl_env_ptr env;
    argv[0] = "";    // cl_boot(argc, argv);
	printf("Entering slave thread\n");
	GC_register_my_thread(argv);

	// This fixes a wrong initialization of GC_stackbottom
	// that only happens in OS X
	GC_stackbottom = (void*)(argv+255);

	ecl_set_option(ECL_OPT_TRAP_SIGSEGV, 0);
	ecl_set_option(ECL_OPT_TRAP_SIGFPE, 0);
	ecl_set_option(ECL_OPT_TRAP_SIGSEGV, 0);
	ecl_set_option(ECL_OPT_TRAP_SIGINT, 0);
	ecl_set_option(ECL_OPT_TRAP_SIGILL, 0);
	ecl_set_option(ECL_OPT_TRAP_SIGBUS, 0);
	ecl_set_option(ECL_OPT_TRAP_INTERRUPT_SIGNAL, 0);
	ecl_set_option(ECL_OPT_SIGNAL_HANDLING_THREAD, 0);
	ecl_set_option(ECL_OPT_INCREMENTAL_GC, 0);
	
	cl_boot(argc,argv);
	env = ecl_process_env();

	// Lisp command loop
	CL_CATCH_ALL_BEGIN(env) {
		do {
			char *command = (char *)comm_read(slave_pipe);
			if (command) {
				cl_object c = c_string_to_object(command);
				printf("%s\n", command);
				cl_print(1,c);
				comm_write_int(master_pipe, ecl_length(c));
			} else {
				break;
			}
		} while (1);
	} CL_CATCH_ALL_END;

	// Shut down ECL and remove links with garbage collector
	cl_shutdown();
	GC_unregister_my_thread();
	printf("Exited slave thread\n");
	return NULL;
}

#endif // EMBED_ECL

void InitPlugin()
{
#undef pthread_create
#ifdef EMBED_ECL
	printf("Init thread: %p\n", (void*)pthread_self());
	comm_open(slave_pipe);
	comm_open(master_pipe);
	pthread_create(&ecl_thread, NULL, ecl_thread_entry, NULL);
	printf("Finished initialization\n");
#endif
}

void DeinitPlugin()
{
#ifdef EMBED_ECL
	comm_write(slave_pipe, NULL);
	comm_close(slave_pipe);
	comm_close(master_pipe);
	printf("DeinitPlugin() exited\n");
#endif
}

--
Instituto de Física Fundamental, CSIC
c/ Serrano, 113b, Madrid 28006 (Spain)
http://juanjose.garciaripoll.googlepages.com




More information about the ecl-devel mailing list