Mercurial > projects > ldc
view runtime/internal/genobj.d @ 556:c23f4cfe4f2b
Link in pthread, dl and m on OS X.
author | Christian Kamm <kamm incasoftware de> |
---|---|
date | Fri, 29 Aug 2008 14:11:20 +0200 |
parents | 44f08170f4ef |
children | eef8ac26c66c |
line wrap: on
line source
/** * Part of the D programming language runtime library. * Forms the symbols available to all D programs. Includes * Object, which is the root of the class object hierarchy. * * This module is implicitly imported. * Macros: * WIKI = Object */ /* * Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com * Written by Walter Bright * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, in both source and binary form, subject to the following * restrictions: * * o The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * o Altered source versions must be plainly marked as such, and must not * be misrepresented as being the original software. * o This notice may not be removed or altered from any source * distribution. */ /* * Modified by Sean Kelly <sean@f4.ca> for use with Tango. * Modified by Tomas Lindquist Olsen <tomas@famolsen.dk> for use with LLVMDC. */ module object; //debug=PRINTF private { import tango.stdc.string; // : memcmp, memcpy, memmove; import tango.stdc.stdlib; // : calloc, realloc, free; import util.string; debug(PRINTF) import tango.stdc.stdio; // : printf; extern (C) void onOutOfMemoryError(); extern (C) Object _d_newclass(ClassInfo ci); } // NOTE: For some reason, this declaration method doesn't work // in this particular file (and this file only). It must // be a DMD thing. //alias typeof(int.sizeof) size_t; //alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t; version( LLVM64 ) { alias ulong size_t; alias long ptrdiff_t; } else { alias uint size_t; alias int ptrdiff_t; } alias size_t hash_t; /** * All D class objects inherit from Object. */ class Object { /** * Convert Object to a human readable string. */ char[] toString() { return this.classinfo.name; } /** * Compute hash function for Object. */ hash_t toHash() { // BUG: this prevents a compacting GC from working, needs to be fixed return cast(hash_t)cast(void*)this; } /** * Compare with another Object obj. * Returns: * $(TABLE * $(TR $(TD this < obj) $(TD < 0)) * $(TR $(TD this == obj) $(TD 0)) * $(TR $(TD this > obj) $(TD > 0)) * ) */ int opCmp(Object o) { // BUG: this prevents a compacting GC from working, needs to be fixed //return cast(int)cast(void*)this - cast(int)cast(void*)o; //throw new Exception("need opCmp for class " ~ this.classinfo.name); return this !is o; } /** * Returns !=0 if this object does have the same contents as obj. */ int opEquals(Object o) { return cast(int)(this is o); } interface Monitor { void lock(); void unlock(); } } /** * Information about an interface. * When an object is accessed via an interface, an Interface* appears as the * first entry in its vtbl. */ struct Interface { ClassInfo classinfo; /// .classinfo for this interface (not for containing class) void*[] vtbl; ptrdiff_t offset; /// offset to Interface 'this' from Object 'this' } /** * Runtime type information about a class. Can be retrieved for any class type * or instance by using the .classinfo property. * A pointer to this appears as the first entry in the class's vtbl[]. */ class ClassInfo : Object { byte[] init; /** class static initializer * (init.length gives size in bytes of class) */ char[] name; /// class name void*[] vtbl; /// virtual function pointer table Interface[] interfaces; /// interfaces this class implements ClassInfo base; /// base class void* destructor; void function(Object) classInvariant; uint flags; // 1: // IUnknown // 2: // has no possible pointers into GC memory // 4: // has offTi[] member // 8: // has constructors void* deallocator; OffsetTypeInfo[] offTi; void function(Object) defaultConstructor; // default Constructor /** * Search all modules for ClassInfo corresponding to classname. * Returns: null if not found */ static ClassInfo find(char[] classname) { foreach (m; ModuleInfo) { //writefln("module %s, %d", m.name, m.localClasses.length); foreach (c; m.localClasses) { //writefln("\tclass %s", c.name); if (c.name == classname) return c; } } return null; } /** * Create instance of Object represented by 'this'. */ Object create() { if (flags & 8 && !defaultConstructor) return null; Object o = _d_newclass(this); if (flags & 8 && defaultConstructor) { defaultConstructor(o); } return o; } } /** * Array of pairs giving the offset and type information for each * member in an aggregate. */ struct OffsetTypeInfo { size_t offset; /// Offset of member from start of object TypeInfo ti; /// TypeInfo for this member } /** * Runtime type information about a type. * Can be retrieved for any type using a * <a href="../expression.html#typeidexpression">TypeidExpression</a>. */ class TypeInfo { hash_t toHash() { hash_t hash; foreach (char c; this.toString()) hash = hash * 9 + c; return hash; } int opCmp(Object o) { if (this is o) return 0; TypeInfo ti = cast(TypeInfo)o; if (ti is null) return 1; return stringCompare(this.toString(), ti.toString()); } int opEquals(Object o) { /* TypeInfo instances are singletons, but duplicates can exist * across DLL's. Therefore, comparing for a name match is * sufficient. */ if (this is o) return 1; TypeInfo ti = cast(TypeInfo)o; return cast(int)(ti && this.toString() == ti.toString()); } /// Returns a hash of the instance of a type. hash_t getHash(void *p) { return cast(hash_t)p; } /// Compares two instances for equality. int equals(void *p1, void *p2) { return cast(int)(p1 == p2); } /// Compares two instances for <, ==, or >. int compare(void *p1, void *p2) { return 0; } /// Returns size of the type. size_t tsize() { return 0; } /// Swaps two instances of the type. void swap(void *p1, void *p2) { size_t n = tsize(); for (size_t i = 0; i < n; i++) { byte t; t = (cast(byte *)p1)[i]; (cast(byte *)p1)[i] = (cast(byte *)p2)[i]; (cast(byte *)p2)[i] = t; } } /// Get TypeInfo for 'next' type, as defined by what kind of type this is, /// null if none. TypeInfo next() { return null; } /// Return default initializer, null if default initialize to 0 void[] init() { return null; } /// Get flags for type: 1 means GC should scan for pointers uint flags() { return 0; } /// Get type information on the contents of the type; null if not available OffsetTypeInfo[] offTi() { return null; } } class TypeInfo_Typedef : TypeInfo { char[] toString() { return name; } int opEquals(Object o) { TypeInfo_Typedef c; return cast(int) (this is o || ((c = cast(TypeInfo_Typedef)o) !is null && this.name == c.name && this.base == c.base)); } hash_t getHash(void *p) { return base.getHash(p); } int equals(void *p1, void *p2) { return base.equals(p1, p2); } int compare(void *p1, void *p2) { return base.compare(p1, p2); } size_t tsize() { return base.tsize(); } void swap(void *p1, void *p2) { return base.swap(p1, p2); } TypeInfo next() { return base; } uint flags() { return base.flags(); } void[] init() { return m_init.length ? m_init : base.init(); } TypeInfo base; char[] name; void[] m_init; } class TypeInfo_Enum : TypeInfo_Typedef { } class TypeInfo_Pointer : TypeInfo { char[] toString() { return m_next.toString() ~ "*"; } int opEquals(Object o) { TypeInfo_Pointer c; return this is o || ((c = cast(TypeInfo_Pointer)o) !is null && this.m_next == c.m_next); } hash_t getHash(void *p) { return cast(hash_t)*cast(void**)p; } int equals(void *p1, void *p2) { return cast(int)(*cast(void* *)p1 == *cast(void* *)p2); } int compare(void *p1, void *p2) { if (*cast(void* *)p1 < *cast(void* *)p2) return -1; else if (*cast(void* *)p1 > *cast(void* *)p2) return 1; else return 0; } size_t tsize() { return (void*).sizeof; } void swap(void *p1, void *p2) { void* tmp; tmp = *cast(void**)p1; *cast(void**)p1 = *cast(void**)p2; *cast(void**)p2 = tmp; } TypeInfo next() { return m_next; } uint flags() { return 1; } TypeInfo m_next; } class TypeInfo_Array : TypeInfo { char[] toString() { return value.toString() ~ "[]"; } int opEquals(Object o) { TypeInfo_Array c; return cast(int) (this is o || ((c = cast(TypeInfo_Array)o) !is null && this.value == c.value)); } hash_t getHash(void *p) { size_t sz = value.tsize(); hash_t hash = 0; void[] a = *cast(void[]*)p; for (size_t i = 0; i < a.length; i++) hash += value.getHash(a.ptr + i * sz); return hash; } int equals(void *p1, void *p2) { void[] a1 = *cast(void[]*)p1; void[] a2 = *cast(void[]*)p2; if (a1.length != a2.length) return 0; size_t sz = value.tsize(); for (size_t i = 0; i < a1.length; i++) { if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz)) return 0; } return 1; } int compare(void *p1, void *p2) { void[] a1 = *cast(void[]*)p1; void[] a2 = *cast(void[]*)p2; size_t sz = value.tsize(); size_t len = a1.length; if (a2.length < len) len = a2.length; for (size_t u = 0; u < len; u++) { int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz); if (result) return result; } return cast(int)a1.length - cast(int)a2.length; } size_t tsize() { return (void[]).sizeof; } void swap(void *p1, void *p2) { void[] tmp; tmp = *cast(void[]*)p1; *cast(void[]*)p1 = *cast(void[]*)p2; *cast(void[]*)p2 = tmp; } TypeInfo value; TypeInfo next() { return value; } uint flags() { return 1; } } class TypeInfo_StaticArray : TypeInfo { char[] toString() { char [10] tmp = void; return value.toString() ~ "[" ~ intToUtf8(tmp, len) ~ "]"; } int opEquals(Object o) { TypeInfo_StaticArray c; return cast(int) (this is o || ((c = cast(TypeInfo_StaticArray)o) !is null && this.len == c.len && this.value == c.value)); } hash_t getHash(void *p) { size_t sz = value.tsize(); hash_t hash = 0; for (size_t i = 0; i < len; i++) hash += value.getHash(p + i * sz); return hash; } int equals(void *p1, void *p2) { size_t sz = value.tsize(); for (size_t u = 0; u < len; u++) { if (!value.equals(p1 + u * sz, p2 + u * sz)) return 0; } return 1; } int compare(void *p1, void *p2) { size_t sz = value.tsize(); for (size_t u = 0; u < len; u++) { int result = value.compare(p1 + u * sz, p2 + u * sz); if (result) return result; } return 0; } size_t tsize() { return len * value.tsize(); } void swap(void *p1, void *p2) { void* tmp; size_t sz = value.tsize(); ubyte[16] buffer; void* pbuffer; if (sz < buffer.sizeof) tmp = buffer.ptr; else tmp = pbuffer = (new void[sz]).ptr; for (size_t u = 0; u < len; u += sz) { size_t o = u * sz; memcpy(tmp, p1 + o, sz); memcpy(p1 + o, p2 + o, sz); memcpy(p2 + o, tmp, sz); } if (pbuffer) delete pbuffer; } void[] init() { return value.init(); } TypeInfo next() { return value; } uint flags() { return value.flags(); } TypeInfo value; size_t len; } class TypeInfo_AssociativeArray : TypeInfo { char[] toString() { return next.toString() ~ "[" ~ key.toString() ~ "]"; } int opEquals(Object o) { TypeInfo_AssociativeArray c; return this is o || ((c = cast(TypeInfo_AssociativeArray)o) !is null && this.key == c.key && this.value == c.value); } // BUG: need to add the rest of the functions size_t tsize() { return (char[int]).sizeof; } TypeInfo next() { return value; } uint flags() { return 1; } TypeInfo value; TypeInfo key; } class TypeInfo_Function : TypeInfo { char[] toString() { return next.toString() ~ "()"; } int opEquals(Object o) { TypeInfo_Function c; return this is o || ((c = cast(TypeInfo_Function)o) !is null && this.next == c.next); } // BUG: need to add the rest of the functions size_t tsize() { return 0; // no size for functions } TypeInfo next; } class TypeInfo_Delegate : TypeInfo { char[] toString() { return next.toString() ~ " delegate()"; } int opEquals(Object o) { TypeInfo_Delegate c; return this is o || ((c = cast(TypeInfo_Delegate)o) !is null && this.next == c.next); } // BUG: need to add the rest of the functions size_t tsize() { alias int delegate() dg; return dg.sizeof; } uint flags() { return 1; } TypeInfo next; } class TypeInfo_Class : TypeInfo { char[] toString() { return info.name; } int opEquals(Object o) { TypeInfo_Class c; return this is o || ((c = cast(TypeInfo_Class)o) !is null && this.info.name == c.classinfo.name); } hash_t getHash(void *p) { Object o = *cast(Object*)p; return o ? o.toHash() : 0; } int equals(void *p1, void *p2) { Object o1 = *cast(Object*)p1; Object o2 = *cast(Object*)p2; return (o1 is o2) || (o1 && o1.opEquals(o2)); } int compare(void *p1, void *p2) { Object o1 = *cast(Object*)p1; Object o2 = *cast(Object*)p2; int c = 0; // Regard null references as always being "less than" if (o1 !is o2) { if (o1) { if (!o2) c = 1; else c = o1.opCmp(o2); } else c = -1; } return c; } size_t tsize() { return Object.sizeof; } uint flags() { return 1; } OffsetTypeInfo[] offTi() { return (info.flags & 4) ? info.offTi : null; } ClassInfo info; } class TypeInfo_Interface : TypeInfo { char[] toString() { return info.name; } int opEquals(Object o) { TypeInfo_Interface c; return this is o || ((c = cast(TypeInfo_Interface)o) !is null && this.info.name == c.classinfo.name); } hash_t getHash(void *p) { Interface* pi = **cast(Interface ***)*cast(void**)p; Object o = cast(Object)(*cast(void**)p - pi.offset); assert(o); return o.toHash(); } int equals(void *p1, void *p2) { Interface* pi = **cast(Interface ***)*cast(void**)p1; Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); pi = **cast(Interface ***)*cast(void**)p2; Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); return o1 == o2 || (o1 && o1.opCmp(o2) == 0); } int compare(void *p1, void *p2) { Interface* pi = **cast(Interface ***)*cast(void**)p1; Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); pi = **cast(Interface ***)*cast(void**)p2; Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); int c = 0; // Regard null references as always being "less than" if (o1 != o2) { if (o1) { if (!o2) c = 1; else c = o1.opCmp(o2); } else c = -1; } return c; } size_t tsize() { return Object.sizeof; } uint flags() { return 1; } ClassInfo info; } class TypeInfo_Struct : TypeInfo { char[] toString() { return name; } int opEquals(Object o) { TypeInfo_Struct s; return this is o || ((s = cast(TypeInfo_Struct)o) !is null && this.name == s.name && this.init.length == s.init.length); } hash_t getHash(void *p) { hash_t h; assert(p); if (xtoHash) { debug(PRINTF) printf("getHash() using xtoHash\n"); h = (*xtoHash)(p); } else { debug(PRINTF) printf("getHash() using default hash\n"); // A sorry hash algorithm. // Should use the one for strings. // BUG: relies on the GC not moving objects for (size_t i = 0; i < m_init.length; i++) { h = h * 9 + *cast(ubyte*)p; p++; } } return h; } int equals(void *p1, void *p2) { int c; if (p1 == p2) c = 1; else if (!p1 || !p2) c = 0; else if (xopEquals) c = (*xopEquals)(p1, p2); else // BUG: relies on the GC not moving objects c = (memcmp(p1, p2, m_init.length) == 0); return c; } int compare(void *p1, void *p2) { int c = 0; // Regard null references as always being "less than" if (p1 != p2) { if (p1) { if (!p2) c = 1; else if (xopCmp) c = (*xopCmp)(p1, p2); else // BUG: relies on the GC not moving objects c = memcmp(p1, p2, m_init.length); } else c = -1; } return c; } size_t tsize() { return m_init.length; } void[] init() { return m_init; } uint flags() { return m_flags; } char[] name; void[] m_init; // initializer; never null hash_t function(void*) xtoHash; int function(void*,void*) xopEquals; int function(void*,void*) xopCmp; char[] function(void*) xtoString; uint m_flags; } class TypeInfo_Tuple : TypeInfo { TypeInfo[] elements; char[] toString() { char[] s; s = "("; foreach (i, element; elements) { if (i) s ~= ','; s ~= element.toString(); } s ~= ")"; return s; } int opEquals(Object o) { if (this is o) return 1; auto t = cast(TypeInfo_Tuple)o; if (t && elements.length == t.elements.length) { for (size_t i = 0; i < elements.length; i++) { if (elements[i] != t.elements[i]) return 0; } return 1; } return 0; } hash_t getHash(void *p) { assert(0); } int equals(void *p1, void *p2) { assert(0); } int compare(void *p1, void *p2) { assert(0); } size_t tsize() { assert(0); } void swap(void *p1, void *p2) { assert(0); } } //////////////////////////////////////////////////////////////////////////////// // Exception //////////////////////////////////////////////////////////////////////////////// class Exception : Object { interface TraceInfo { int opApply( int delegate( inout char[] ) ); } char[] msg; char[] file; size_t line; TraceInfo info; Exception next; this( char[] msg, Exception next = null ) { this.msg = msg; this.next = next; this.info = traceContext(); } this( char[] msg, char[] file, size_t line, Exception next = null ) { this(msg, next); this.file = file; this.line = line; this.info = traceContext(); } char[] toString() { return msg; } } alias Exception.TraceInfo function( void* ptr = null ) TraceHandler; private TraceHandler traceHandler = null; /** * Overrides the default trace hander with a user-supplied version. * * Params: * h = The new trace handler. Set to null to use the default handler. */ extern (C) void rt_setTraceHandler( TraceHandler h ) { traceHandler = h; } /** * This function will be called when an Exception is constructed. The * user-supplied trace handler will be called if one has been supplied, * otherwise no trace will be generated. * * Params: * ptr = A pointer to the location from which to generate the trace, or null * if the trace should be generated from within the trace handler * itself. * * Returns: * An object describing the current calling context or null if no handler is * supplied. */ Exception.TraceInfo traceContext( void* ptr = null ) { if( traceHandler is null ) return null; return traceHandler( ptr ); } //////////////////////////////////////////////////////////////////////////////// // ModuleInfo //////////////////////////////////////////////////////////////////////////////// enum { MIctorstart = 1, // we've started constructing it MIctordone = 2, // finished construction MIstandalone = 4, // module ctor does not depend on other module // ctors being done first MIhasictor = 8, // has ictor member } class ModuleInfo { char[] name; ModuleInfo[] importedModules; ClassInfo[] localClasses; uint flags; void function() ctor; // module static constructor (order dependent) void function() dtor; // module static destructor void function() unitTest; // module unit tests void* xgetMembers; // module getMembers() function void function() ictor; // module static constructor (order independent) static int opApply( int delegate( inout ModuleInfo ) dg ) { int ret = 0; foreach( m; _moduleinfo_array ) { ret = dg( m ); if( ret ) break; } return ret; } } // this gets initialized in _moduleCtor() extern (C) ModuleInfo[] _moduleinfo_array; // This linked list is created by a compiler generated function inserted // into the .ctor list by the compiler. struct ModuleReference { ModuleReference* next; ModuleInfo mod; } extern (C) ModuleReference* _Dmodule_ref; // start of linked list // this list is built from the linked list above ModuleInfo[] _moduleinfo_dtors; uint _moduleinfo_dtors_i; /** * Initialize the modules. */ extern (C) void _moduleCtor() { debug(PRINTF) printf("_moduleCtor()\n"); int len = 0; ModuleReference *mr; for (mr = _Dmodule_ref; mr; mr = mr.next) len++; _moduleinfo_array = new ModuleInfo[len]; len = 0; for (mr = _Dmodule_ref; mr; mr = mr.next) { _moduleinfo_array[len] = mr.mod; len++; } _moduleinfo_dtors = new ModuleInfo[_moduleinfo_array.length]; debug(PRINTF) printf("_moduleinfo_dtors = x%x\n", cast(void *)_moduleinfo_dtors); _moduleIndependentCtors(); _moduleCtor2(_moduleinfo_array, 0); } extern (C) void _moduleIndependentCtors() { debug(PRINTF) printf("_moduleIndependentCtors()\n"); foreach (m; _moduleinfo_array) { if (m && m.flags & MIhasictor && m.ictor) { (*m.ictor)(); } } debug(PRINTF) printf("_moduleIndependentCtors() DONE\n"); } void _moduleCtor2(ModuleInfo[] mi, int skip) { debug(PRINTF) printf("_moduleCtor2(): %d modules\n", mi.length); for (uint i = 0; i < mi.length; i++) { ModuleInfo m = mi[i]; debug(PRINTF) printf("\tmodule[%d] = '%p'\n", i, m); if (!m) continue; debug(PRINTF) printf("\tmodule[%d] = '%.*s'\n", i, m.name.length, m.name.ptr); if (m.flags & MIctordone) continue; debug(PRINTF) printf("\tmodule[%d] = '%.*s', m = x%x\n", i, m.name.length, m.name.ptr, m); if (m.ctor || m.dtor) { if (m.flags & MIctorstart) { if (skip || m.flags & MIstandalone) continue; throw new Exception( "Cyclic dependency in module " ~ m.name ); } m.flags |= MIctorstart; _moduleCtor2(m.importedModules, 0); if (m.ctor) (*m.ctor)(); m.flags &= ~MIctorstart; m.flags |= MIctordone; // Now that construction is done, register the destructor //printf("\tadding module dtor x%x\n", m); assert(_moduleinfo_dtors_i < _moduleinfo_dtors.length); _moduleinfo_dtors[_moduleinfo_dtors_i++] = m; } else { m.flags |= MIctordone; _moduleCtor2(m.importedModules, 1); } } debug(PRINTF) printf("_moduleCtor2() DONE\n"); } /** * Destruct the modules. */ // Starting the name with "_STD" means under linux a pointer to the // function gets put in the .dtors segment. extern (C) void _moduleDtor() { debug(PRINTF) printf("_moduleDtor(): %d modules\n", _moduleinfo_dtors_i); for (uint i = _moduleinfo_dtors_i; i-- != 0;) { ModuleInfo m = _moduleinfo_dtors[i]; debug(PRINTF) printf("\tmodule[%d] = '%.*s', x%x\n", i, m.name, m); if (m.dtor) { (*m.dtor)(); } } debug(PRINTF) printf("_moduleDtor() done\n"); } //////////////////////////////////////////////////////////////////////////////// // Monitor //////////////////////////////////////////////////////////////////////////////// alias Object.Monitor IMonitor; alias void delegate(Object) DEvent; // NOTE: The dtor callback feature is only supported for monitors that are not // supplied by the user. The assumption is that any object with a user- // supplied monitor may have special storage or lifetime requirements and // that as a result, storing references to local objects within Monitor // may not be safe or desirable. Thus, devt is only valid if impl is // null. struct Monitor { IMonitor impl; /* internal */ DEvent[] devt; /* stuff */ } Monitor* getMonitor(Object h) { return cast(Monitor*) (cast(void**) h)[1]; } void setMonitor(Object h, Monitor* m) { (cast(void**) h)[1] = m; } extern (C) void _d_monitor_create(Object); extern (C) void _d_monitor_destroy(Object); extern (C) void _d_monitor_lock(Object); extern (C) int _d_monitor_unlock(Object); extern (C) void _d_monitordelete(Object h, bool det) { Monitor* m = getMonitor(h); if (m !is null) { IMonitor i = m.impl; if (i is null) { _d_monitor_devt(m, h); _d_monitor_destroy(h); setMonitor(h, null); return; } if (det && (cast(void*) i) !is (cast(void*) h)) delete i; setMonitor(h, null); } } extern (C) void _d_monitorenter(Object h) { Monitor* m = getMonitor(h); if (m is null) { _d_monitor_create(h); m = getMonitor(h); } IMonitor i = m.impl; if (i is null) { _d_monitor_lock(h); return; } i.lock(); } extern (C) void _d_monitorexit(Object h) { Monitor* m = getMonitor(h); IMonitor i = m.impl; if (i is null) { _d_monitor_unlock(h); return; } i.unlock(); } extern (C) void _d_monitor_devt(Monitor* m, Object h) { if (m.devt.length) { DEvent[] devt; synchronized (h) { devt = m.devt; m.devt = null; } foreach (v; devt) { if (v) v(h); } free(devt.ptr); } } extern (C) void rt_attachDisposeEvent(Object h, DEvent e) { synchronized (h) { Monitor* m = getMonitor(h); assert(m.impl is null); foreach (inout v; m.devt) { if (v is null || v == e) { v = e; return; } } auto len = m.devt.length + 4; // grow by 4 elements auto pos = m.devt.length; // insert position auto p = realloc(m.devt.ptr, DEvent.sizeof * len); if (!p) onOutOfMemoryError(); m.devt = (cast(DEvent*)p)[0 .. len]; m.devt[pos+1 .. len] = null; m.devt[pos] = e; } } extern (C) void rt_detachDisposeEvent(Object h, DEvent e) { synchronized (h) { Monitor* m = getMonitor(h); assert(m.impl is null); foreach (p, v; m.devt) { if (v == e) { memmove(&m.devt[p], &m.devt[p+1], (m.devt.length - p - 1) * DEvent.sizeof); m.devt[$ - 1] = null; return; } } } }