Thread overview
Using D from C
Aug 21, 2005
Artem Gr
Aug 24, 2005
Thomas Kühne
Aug 31, 2005
Carlos Santander
Aug 31, 2005
Thomas Kühne
Sep 01, 2005
Carlos Santander
Sep 02, 2005
Thomas Kühne
Sep 03, 2005
Carlos Santander
Sep 03, 2005
Thomas Kühne
August 21, 2005
Is there some function to initialize the D,
like JvCreateJavaVM in GCJ CNI?

8<--- Test.d ------->8

class DeeTest {
  void test(){
    printf( "D" );
  }
}
extern( C ){
  void testFunction(){
    DeeTest deeTest = new DeeTest();
    deeTest.test();
  }
}

8<--- main.c ------->8

void testFunction();
int main( char** argv, int argc ){
  testFunction();
  return 0;
}

8<--- Problem ------->8

(gdb) run
Starting program: /home/Glim/dee/c_test.exe

Program received signal SIGSEGV, Segmentation fault.
0x0040311c in _d_newclass ()
(gdb) bt
#0  0x0040311c in _d_newclass ()
#1  0x004010c1 in testFunction () at ru/glim/deetest/Test.d:8
#2  0x0040107f in main (argv=0x1, argc=4726336) at main.c:3
(gdb)
August 24, 2005
Artem Gr schrieb:
> 
> Is there some function to initialize the D,
> like JvCreateJavaVM in GCJ CNI?

Have a look at the code below.

Thomas

==========

dmd -c phobosc.d some.d
gcc -o main main.c some.o phobosc.o -lphobos -lpthread -lm
./main


=====phobosc.d=====
/*
	enable access to D code from C

	Copyright (C) 2005 Thomas Kuehne <thomas@kuehne.cn>

Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:

    1. Redistributions of source code must retain the above copyright

       notice, definition, disclaimer, and this list of conditions.

    2. Redistributions in binary form must reproduce the above copyright
       notice, definition, disclaimer, and this list of conditions in
       documentation and/or other materials provided with the
       distribution.

    3. Altered versions must be plainly marked as such
       and must not be misrepresented as being the original source.

*/

module kuehne.phobosc;

private{
	import std.c.stdio;
	import std.c.stdlib;

	extern (C) void _STI_monitor_staticctor();
	extern (C) void _STD_monitor_staticdtor();
	extern (C) void _STI_critical_init();
	extern (C) void _STD_critical_term();
	extern (C) void gc_init();
	extern (C) void gc_term();
	extern (C) void _minit();
	extern (C) void _moduleCtor();
	extern (C) void _moduleDtor();
	extern (C) void _moduleUnitTests();

	// sometimes required by the linker
	extern(C) void* _deh_beg;
	extern(C) void *_deh_end;

	// protect D memory against GC
	size_t[void*] memoryGuard;
	Object sync;

	// cope with multiple inits & unloads
	size_t loadCount;
}

/* call before the use of any D code
 * multiple calls
 */
public extern(C) int loadPhobos(){
	if(loadCount==0){
		version (linux){
			_STI_monitor_staticctor();
			_STI_critical_init();
			gc_init();
		}

		version (Win32){
			gc_init();
			_minit();
		}

		try{
			_moduleCtor();
			_moduleUnitTests();
			sync = new Object();
		}catch(Object o){
			fprintf(stderr, "Error: %.*s", o.toString());
			return 0;
		}
	}

	loadCount++;

	return 0;
}

public extern(C) void unloadPhobos(){
	if(loadCount==1){
		_moduleDtor();
		gc_term();
		version (linux){

			_STD_critical_term();
			_STD_monitor_staticdtor();
		}

	}

	if(loadCount>0){
		loadCount--;
	}
}

/* protect memory allocated by D's GC to be collected
 * while storing the memory in some C code
 */
public extern(C) void markMemoryFromD(void* ptr){
	synchronized(sync){
		if(ptr in memoryGuard){
			memoryGuard[ptr]+=1;
		}else{
			memoryGuard[ptr]=1;
		}
	}
}

/* remove GC collection guard if no further mark is set
 */
public extern(C) void unmarkMemoryFromD(void* ptr){
	synchronized(sync){
		if(ptr in memoryGuard){
			if(--memoryGuard[ptr] == 0){
				memoryGuard.remove(ptr);
			}
		}
	}
}

/* remove GC collection guard
 */
public extern(C) void forceUnmarkMemoryFromD(void* ptr){
	if(ptr in memoryGuard){
		memoryGuard.remove(ptr);
	}
}

=====phobosc.h=====
#ifndef PHOBOSC_H
#define PHOBOSC_H

int loadPhobos();
void unloadPhobos();
void markMemoryFromD(void* ptr);
void unmarkMemoryFromD(void* ptr);
void forceUnmarkMemoryFromD(void* ptr);

#endif

=====main.c=====
#include "phobosc.h"

extern void* _D4some5test1FZC1c6Sample(); // D linkage
extern void* test2(void*); // C linkage

int main(){
	loadPhobos();

	void* a = _D1c5test1FZC1c6Sample();
	markMemoryFromD(a);

	void* b = _D1c5test1FZC1c6Sample();
	markMemoryFromD(b);

	test2(a);
	test2(a);
	test2(b);
	test2(a);

	unmarkMemoryFromD(a);
	unmarkMemoryFromD(b);

	unloadPhobos();
	return 0;
}

=====some.d====
module some;
import std.stdio;

class Sample : Object{
	int id;
	static int idCounter;

	this(){
		id=(idCounter++);
	}
}

Sample test1(){
	Sample o = new Sample;
	writef("test1 id:%s\n", o.id);
	return o;
}

extern(C) void test2(Sample o){
	writef("test2 id:%s\n", o.id);
}
August 31, 2005
Thomas Kühne escribió:
> private{
> 	import std.c.stdio;
> 	import std.c.stdlib;
> 
> 	extern (C) void _STI_monitor_staticctor();
> 	extern (C) void _STD_monitor_staticdtor();
> 	extern (C) void _STI_critical_init();
> 	extern (C) void _STD_critical_term();
> 	extern (C) void gc_init();
> 	extern (C) void gc_term();
> 	extern (C) void _minit();
> 	extern (C) void _moduleCtor();
> 	extern (C) void _moduleDtor();
> 	extern (C) void _moduleUnitTests();
> 
> 	// sometimes required by the linker
> 	extern(C) void* _deh_beg;
> 	extern(C) void *_deh_end;
> 
> 	// protect D memory against GC
> 	size_t[void*] memoryGuard;
> 	Object sync;
> 
> 	// cope with multiple inits & unloads
> 	size_t loadCount;
> }
> 
> /* call before the use of any D code
>  * multiple calls
>  */
> public extern(C) int loadPhobos(){
> 	if(loadCount==0){
> 		version (linux){
> 			_STI_monitor_staticctor();
> 			_STI_critical_init();
> 			gc_init();
> 		}
> 
> 		version (Win32){
> 			gc_init();
> 			_minit();
> 		}
> 
> 		try{
> 			_moduleCtor();
> 			_moduleUnitTests();
> 			sync = new Object();
> 		}catch(Object o){
> 			fprintf(stderr, "Error: %.*s", o.toString());
> 			return 0;
> 		}
> 	}
> 
> 	loadCount++;
> 
> 	return 0;
> }
> 
> public extern(C) void unloadPhobos(){
> 	if(loadCount==1){
> 		_moduleDtor();
> 		gc_term();
> 		version (linux){
> 
> 			_STD_critical_term();
> 			_STD_monitor_staticdtor();
> 		}
> 
> 	}
> 
> 	if(loadCount>0){
> 		loadCount--;
> 	}
> }
> 

I'm trying to do this but from C but Pascal (using FreePascal 2.0.0) on Mac OS X 10.3.9, but I get "Bus error" all the time. gdb shows this:

Program received signal EXC_BAD_ACCESS, Could not access memory.
0x9001f898 in malloc_create_zone ()
(gdb) bt
#0  0x9001f898 in malloc_create_zone ()
#1  0x9002c424 in _malloc_initialize ()
#2  0x90001a00 in malloc ()
#3  0x000042e8 in gc_init () at ../../../gcc-3.4.3/libphobos/internal/gc/gc.d:106
#4  0x00001958 in Dinit () at d.d:32
#5  0x8fe1a278 in __dyld__dyld_start ()

Any ideas?

-- 
Carlos Santander Bernal
August 31, 2005
Carlos Santander schrieb:
[snip]

> I'm trying to do this but from C but Pascal (using FreePascal 2.0.0) on Mac OS X 10.3.9, but I get "Bus error" all the time. gdb shows this:
> 
> Program received signal EXC_BAD_ACCESS, Could not access memory.
> 0x9001f898 in malloc_create_zone ()
> (gdb) bt
> #0  0x9001f898 in malloc_create_zone ()
> #1  0x9002c424 in _malloc_initialize ()
> #2  0x90001a00 in malloc ()
> #3  0x000042e8 in gc_init () at
> ../../../gcc-3.4.3/libphobos/internal/gc/gc.d:106
> #4  0x00001958 in Dinit () at d.d:32
> #5  0x8fe1a278 in __dyld__dyld_start ()
> 
> Any ideas?

Please try the code below - it seems to work on Linux and Windows.

If it isn't working properly compile with "-debug=StdioInit" and/or
execute the sniplet below BEFORE calling
loadPhobos.

Thomas

- --------------------------------------------
private import gcc.gc_guess_stack;

//
// argv from C's: int main(int argc, char **argv)
//
extern(C) setStackOriginGuess(char **argv){
	stackOriginGuess = &argv;
}
- --------------------------------------------

/*
	enable access to D code from C

	Copyright (C) 2005 Thomas Kuehne <thomas@kuehne.cn>

Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:

    1. Redistributions of source code must retain the above copyright
       notice, definition, disclaimer, and this list of conditions.

    2. Redistributions in binary form must reproduce the above copyright
       notice, definition, disclaimer, and this list of conditions in
       documentation and/or other materials provided with the
       distribution.

    3. Altered versions must be plainly marked as such
       and must not be misrepresented as being the original source.

*/

module kuehne.phobosc;

private{
	// only required for error reporting
	import std.c.stdio;
	import std.c.stdlib;

	// cope with DMD's and GDC's version war
	version(Unix){}else version(linux){version=Unix;}

	extern (C) void gc_init();
	extern (C) void gc_term();
	extern (C) void _moduleCtor();
	extern (C) void _moduleDtor();
	extern (C) void _moduleUnitTests();

	version(Unix){
		extern (C) void _STI_monitor_staticctor();
		extern (C) void _STD_monitor_staticdtor();
		extern (C) void _STI_critical_init();
		extern (C) void _STD_critical_term();
	}

	version(Windows){
		extern (C) void _minit();
	}

	// sometimes required by the linker
	extern(C) void* _deh_beg;
	extern(C) void *_deh_end;

	// protect D memory against GC
	size_t[void*] memoryGuard;
	Object sync;

	debug(StdioInit){
		extern(C) void _d_gnu_cbridge_init_stdio();
	}

	// cope with multiple inits & unload
	size_t loadCount;
}

/**
	call before the use of any D code
	multiple calls are harmle

	returns 0 for succe
*/
public extern(C) int loadPhobos(){
	if(loadCount==0){
		version (Windows){
			gc_init();
			_minit();
		}else version(Unix){
			_STI_monitor_staticctor();
			_STI_critical_init();
			gc_init();
		}else{
			pragma(msg, "missing GC init");
			static assert(0);
		}

		debug(StdioInit){
			_d_gnu_cbridge_init_stdio();
		}

		try{
			_moduleCtor();
			_moduleUnitTests();
			sync = new Object();
		}catch(Object o){
			fprintf(stderr, "Error: %.*s", o.toString());
			return 1;
		}
	}

	loadCount++;

	return 0;
}

/**
	don't use any D code or GCed memory after calling thi
	remember to call unloadPhobos as many times as loadPhobos succeeded
*/
public extern(C) void unloadPhobos(){
	if(loadCount==1){
		_moduleDtor();
		gc_term();
		version(Unix){
			_STD_critical_term();
			_STD_monitor_staticdtor();
		}
	}

	if(loadCount>0){
		loadCount--;
	}
}

/**
	protect memory allocated by D's GC to be collected
	while storing the memory in some C code
 */
public extern(C) void markMemoryFromD(void* ptr){
	synchronized(sync){
		size_t* count = ptr in memoryGuard;
		if(count){
			(*count)++;
		}else{
			memoryGuard[ptr]=1;
		}
	}
}

/**
	remove GC collection guard if no further mark is set
 */
public extern(C) void unmarkMemoryFromD(void* ptr){
	synchronized(sync){
		size_t* count = ptr in memoryGuard;
		if(count && (--(*count) == 0)){
			memoryGuard.remove(ptr);
		}
	}
}

/**
	remove GC collection guard
 */
public extern(C) void forceUnmarkMemoryFromD(void* ptr){
	if(ptr in memoryGuard){
		memoryGuard.remove(ptr);
	}
}

September 01, 2005
Thomas Kühne escribió:
> Please try the code below - it seems to work on Linux and Windows.
> 

I get exactly the same as before.

> If it isn't working properly compile with "-debug=StdioInit" and/or

With this, I get:

/usr/bin/ld: Undefined symbols:
__d_gnu_cbridge_init_stdio

> execute the sniplet below BEFORE calling
> loadPhobos.
> 
> Thomas
> 
> - --------------------------------------------
> private import gcc.gc_guess_stack;
> 
> //
> // argv from C's: int main(int argc, char **argv)
> //
> extern(C) setStackOriginGuess(char **argv){
> 	stackOriginGuess = &argv;
> }
> - --------------------------------------------
> 

I suppose this is the sniplet you were referring to.
With this, I get:

/usr/bin/ld: Undefined symbols:
__D3gcc14gc_guess_stack16stackOriginGuessPv

-- 
Carlos Santander Bernal
September 02, 2005
Carlos Santander schrieb:
> Thomas Kühne escribió:
> 
>> Please try the code below - it seems to work on Linux and Windows.
>>
> 
> I get exactly the same as before.
[snip]

I can think of three (more or less) likely possibilities:
1) your ram is messed up
2) malloc is buggy
3) someone is messing up the memory

Let's find out who is at fault:

- -----

gdb ./application
[some license stuff]
(gdb) set env DYLD_INSERT_LIBRARIES /usr/lib/libgmalloc.dylib
(gdb) r
[some crash]
(gdb) bt

- -----

further information: http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/libgmalloc.3.html

Thomas
September 03, 2005
Thomas Kühne escribió:
> 
> [snip]
> 
> I can think of three (more or less) likely possibilities:
> 1) your ram is messed up
> 2) malloc is buggy
> 3) someone is messing up the memory
> 
> Let's find out who is at fault:
> 
> - -----
> 
> gdb ./application
> [some license stuff]
> (gdb) set env DYLD_INSERT_LIBRARIES /usr/lib/libgmalloc.dylib
> (gdb) r
> [some crash]
> (gdb) bt
> 
> - -----
> 
> further information:
> http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/libgmalloc.3.html
> 
> Thomas

I'm sorry, but I don't understand what you're trying to say here. I entered that "set env ..." command but the result was exactly the same. I'm lost by this post...

-- 
Carlos Santander Bernal
September 03, 2005
Carlos Santander schrieb:
> Thomas Kühne escribió:
> 
>>
>> [snip]
>>
>> I can think of three (more or less) likely possibilities:
>> 1) your ram is messed up
>> 2) malloc is buggy
>> 3) someone is messing up the memory
>>
>> Let's find out who is at fault:
>>
>> - -----
>>
>> gdb ./application
>> [some license stuff]
>> (gdb) set env DYLD_INSERT_LIBRARIES /usr/lib/libgmalloc.dylib
>> (gdb) r
>> [some crash]
>> (gdb) bt
>>
>> - -----
>>
>> further information: http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/libgmalloc.3.html
>>
>>
>> Thomas
> 
> 
> I'm sorry, but I don't understand what you're trying to say here. I entered that "set env ..." command but the result was exactly the same. I'm lost by this post...
> 

First of all I assume: neither your RAM nor your kernel are broken

Ok, let's have a look at the backtrace:

> Program received signal EXC_BAD_ACCESS, Could not access memory.
> 0x9001f898 in malloc_create_zone ()
> (gdb) bt
> #0  0x9001f898 in malloc_create_zone ()
> #1  0x9002c424 in _malloc_initialize ()
> #2  0x90001a00 in malloc ()
> #3  0x000042e8 in gc_init () at
>  ../../../gcc-3.4.3/libphobos/internal/gc/gc.d:106
> #4  0x00001958 in Dinit () at d.d:32
> #5  0x8fe1a278 in __dyld__dyld_start ()

Etnries #2 to #0 indicate, that the system call "malloc" exploded.

Neither malloc_create_zone nor _malloc_initialize seem to be properly documented.

As a side note
http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/malloc.3.html
states that malloc should return a NULL pointer if there were any error,
but we aren't even getting to the return stage.


So what does OpenDarwin do? http://darwinsource.opendarwin.org/10.2/Libc-262/gen/malloc.c

> void *malloc(size_t size) {
>    return malloc_zone_malloc(inline_malloc_default_zone(), size);
> }

> static inline malloc_zone_t *inline_malloc_default_zone(void) {
>    if (!malloc_num_zones) _malloc_initialize();
>    return malloc_zones[0];
> }

> static void _malloc_initialize(void) {
>    // guaranteed to be called only once
>    (void)malloc_create_zone(0, 0);
>    malloc_set_zone_name(malloc_zones[0], "DefaultMallocZone");
>    LOCK_INIT(_malloc_lock);
> }

> malloc_zone_t *malloc_create_zone(vm_size_t start_size, unsigned
> flags) {
>    malloc_zone_t	*zone;
>    if (!malloc_num_zones) {
>	char	**env = * _NSGetEnviron();
>	char	**p;
>	char	*c;
>	/* Given that all environment variables start with "Malloc" we
>	optimize by scanning quickly first the environment, therefore
>	avoiding repeated calls to getenv() */
>	for (p = env; (c = *p) != NULL; ++p) {
>	    if (!strncmp(c, "Malloc", 6)) {
>		set_flags_from_environment();
>		break;
>	    }
>	}
>
>    }
>    zone = create_scalable_zone(start_size, malloc_debug_flags);
>    malloc_zone_register(zone);
>    return zone;
> }

Either the following line is the reason or somewhere code before gc.d:106 messed up malloc_zones or malloc_num_zones (e.g by writing past the allocated memory).

	char	**env = * _NSGetEnviron();

Thomas