1 module libssh.threading; 2 3 import core.sync.mutex; 4 import core.thread; 5 import std.algorithm.mutation; 6 7 import libssh.c_bindings.libssh; 8 import libssh.c_bindings.callbacks; 9 import libssh.utils; 10 11 version (LibSSHWithPThreads) { 12 void initWithPThreads() { 13 ssh_threads_set_callbacks(ssh_threads_get_pthread()); 14 ssh_init(); 15 } 16 } 17 18 struct ThreadsCallbacks { 19 string type; 20 bool function(ref void* lock) mutexInit; 21 bool function(ref void* lock) mutexDestroy; 22 bool function(ref void* lock) mutexLock; 23 bool function(ref void* lock) mutexUnlock; 24 uint function() getThreadId; 25 } 26 27 void initWithDLang() { 28 ssh_threads_set_callbacks(&dlangThreadsCallbacks); 29 ssh_init(); 30 } 31 32 void initWithCustom(ThreadsCallbacks cb) { 33 _customCallbacks = cb; 34 libsshCustomThreadsStruct.type = toStrZ(cb.type); 35 ssh_threads_set_callbacks(&libsshCustomThreadsStruct); 36 ssh_init(); 37 } 38 39 private { 40 __gshared Mutex _internalMutex; 41 __gshared Mutex[] _mutexes = []; // To prevent GC collect mutexes sended to libssh 42 43 extern(C) int dlangThreadsMutexInit(void** lock) { 44 auto result = new Mutex(); 45 46 synchronized (_internalMutex) { 47 _mutexes ~= result; 48 } 49 50 *lock = cast(void*) result; 51 return 0; 52 } 53 54 extern(C) int dlangThreadsMutexDestroy(void** lock) { 55 auto mutex = cast(Mutex) (*lock); 56 57 synchronized (_internalMutex) { 58 _mutexes = remove!(a => a == mutex)(_mutexes); 59 } 60 61 delete mutex; 62 *lock = null; 63 64 return 0; 65 } 66 67 extern(C) int dlangThreadsMutexLock(void** lock) { 68 auto mutex = cast(Mutex) (*lock); 69 70 mutex.lock(); 71 72 return 0; 73 } 74 75 extern(C) int dlangThreadsMutexUnlock(void** lock) { 76 auto mutex = cast(Mutex) (*lock); 77 78 mutex.unlock(); 79 80 return 0; 81 } 82 83 extern(C) uint dlangThreadsThreadId() { 84 auto id = Thread.getThis().id; 85 86 // Why? Why not =) I have not better idea to cast thread id to uint from ulong. 87 // As for me - this variant is better than just remove hight part 88 return cast(uint) (((cast(ulong)(id) & 0xffffffff00000000L) >> 32) ^ (cast(uint)(id) & 0xffffffff)); 89 } 90 91 __gshared ssh_threads_callbacks_struct dlangThreadsCallbacks = { 92 type:"dlang" ~ 0, 93 mutex_init: &dlangThreadsMutexInit, 94 mutex_destroy: &dlangThreadsMutexDestroy, 95 mutex_lock: &dlangThreadsMutexLock, 96 mutex_unlock: &dlangThreadsMutexUnlock, 97 thread_id: &dlangThreadsThreadId, 98 }; 99 100 shared static this() { 101 _internalMutex = new Mutex(); 102 } 103 104 105 __gshared ThreadsCallbacks _customCallbacks; 106 107 extern(C) int customThreadsMutexInit(void** lock) { 108 return _customCallbacks.mutexInit(*lock) ? 0 : -1; 109 } 110 111 extern(C) int customThreadsMutexDestroy(void** lock) { 112 return _customCallbacks.mutexDestroy(*lock) ? 0 : -1; 113 } 114 115 extern(C) int customThreadsMutexLock(void** lock) { 116 return _customCallbacks.mutexLock(*lock) ? 0 : -1; 117 } 118 119 extern(C) int customThreadsMutexUnlock(void** lock) { 120 return _customCallbacks.mutexUnlock(*lock) ? 0 : -1; 121 } 122 123 extern(C) uint customThreadsGetThreadId() { 124 return _customCallbacks.getThreadId(); 125 } 126 127 __gshared ssh_threads_callbacks_struct libsshCustomThreadsStruct = { 128 type: null, 129 mutex_init: &customThreadsMutexInit, 130 mutex_destroy: &customThreadsMutexDestroy, 131 mutex_lock: &customThreadsMutexLock, 132 mutex_unlock: &customThreadsMutexUnlock, 133 thread_id: &customThreadsGetThreadId, 134 }; 135 }