diff --git a/Makefile b/Makefile index ea4bf16..f310275 100644 --- a/Makefile +++ b/Makefile @@ -5,11 +5,14 @@ SRC = cwCommonImpl.cpp cwMem.cpp cwLog.cpp cwUtility.cpp HDR += cwFileSys.h cwText.h cwFile.h cwTime.h cwLex.h cwNumericConvert.h SRC += cwFileSys.cpp cwText.cpp cwFile.cpp cwTime.cpp cwLex.cpp -HDR += cwObject.h cwObjectTemplate.h cwTextBuf.h cwThread.h cwMpScNbQueue.h -SRC += cwObject.cpp cwTextBuf.cpp cwThread.cpp +HDR += cwObject.h cwObjectTemplate.h cwTextBuf.h +SRC += cwObject.cpp cwTextBuf.cpp -HDR += cwWebSock.h cwWebSockSvr.h -SRC += cwWebSock.cpp cwWebSockSvr.cpp +HDR += cwThread.h cwMutex.h cwMpScNbQueue.h +SRC += cwThread.cpp cwMutex.cpp + +HDR += cwWebSock.h cwWebSockSvr.h cwLib.h +SRC += cwWebSock.cpp cwWebSockSvr.cpp cwLib.cpp HDR += cwSerialPort.h cwSerialPortSrv.h SRC += cwSerialPort.cpp cwSerialPortSrv.cpp @@ -26,10 +29,11 @@ SRC += cwTcpSocket.cpp cwTcpSocketSrv.cpp cwTcpSocketTest.cpp HDR += cwMdns.h cwEuCon.h cwDnsSd.h dns_sd/dns_sd.h dns_sd/dns_sd_print.h dns_sd/dns_sd_const.h dns_sd/fader.h dns_sd/rpt.h SRC += cwMdns.cpp cwEuCon.cpp cwDnsSd.cpp dns_sd/dns_sd.cpp dns_sd/dns_sd_print.cpp dns_sd/fader.cpp dns_sd/rpt.cpp -HDR += cwIo.h cwIoTest.h +HDR += cwIo.h cwIoTest.h SRC += cwIo.cpp cwIoTest.cpp -LIBS = -lpthread -lwebsockets -lasound +# -ldl = dlopen,dlclose,dlsym +LIBS = -lpthread -lwebsockets -lasound -ldl WS_DIR = /home/kevin/sdk/libwebsockets/build/out INC_PATH = $(WS_DIR)/include diff --git a/cwLib.cpp b/cwLib.cpp new file mode 100644 index 0000000..5bbd1fd --- /dev/null +++ b/cwLib.cpp @@ -0,0 +1,304 @@ +#include "cwCommon.h" +#include "cwLog.h" +#include "cwCommonImpl.h" +#include "cwMem.h" +#include "cwFileSys.h" +#include "cwLib.h" + +#ifdef cwLINUX + +#include + +typedef void* dynLibH_t; + +bool _cmLibIsNull( dynLibH_t lh ) +{ return lh == nullptr; }; + +const char* _cmLibSysError() +{ + const char* msg = dlerror(); + if( msg == nullptr ) + msg = ""; + return msg; +} + +dynLibH_t _cmLibOpen( const char* libFn ) +{ return dlopen(libFn,RTLD_LAZY); } + +const char* _cmLibClose( dynLibH_t* lH ) +{ + if( *lH != nullptr ) + { + if( dlclose(*lH) == 0 ) + *lH = nullptr; + else + return dlerror(); + } + + return nullptr; +} + +void* _cmLibSym( dynLibH_t h, const char* symLabel ) +{ return dlsym(h,symLabel); } + + +#endif + + +namespace cw +{ + namespace lib + { + typedef void* dynLibH_t; + + typedef struct node_str + { + char* fn; // NULL for available nodes + unsigned id; // kInvalidId for available nodes + dynLibH_t dynLibH; // The platform dependent library handle + struct node_str* link; + } node_t; + + typedef struct lib_str + { + node_t* list; // list of open libraries + unsigned id; // next library id + } lib_t; + + lib_t* _handleToPtr( handle_t h ) + { return handleToPtr(h); } + + // Given a library id return the associated node + node_t* _libIdToNode( lib_t* p, unsigned libId ) + { + node_t* np = p->list; + + while( np != nullptr ) + { + if( np->id == libId ) + return np; + + np = np->link; + } + + return nullptr; + } + + // Close a library and make it's node available for reuse + rc_t _closeLib( node_t* np ) + { + rc_t rc = kOkRC; + const char* errMsg = nullptr; + + // tell the system to close the library + if((errMsg = _cmLibClose( &np->dynLibH )) != nullptr ) + rc = cwLogError(kInvalidOpRC,"Library %s close failed. Error:%s.", np->fn, errMsg ); + else + { + // mark the node as available + mem::release(np->fn); + np->id = kInvalidId; + } + + return rc; + } + + // Finalize the library manager + rc_t _finalize( lib_t* p ) + { + rc_t rc = kOkRC; + node_t* np = p->list; + while( np!=nullptr ) + { + node_t* n0p = np->link; + + // close the node's library + rc_t rc0 = _closeLib( np ); + + // store the error code + if( rc0 != kOkRC ) + rc = rc0; + + // release the node + mem::release(np); + + np = n0p; + } + + mem::release(p); + return rc; + } + } +} + +cw::rc_t cw::lib::initialize( handle_t& h, const char* dirStr ) +{ + rc_t rc; + if((rc = finalize(h)) != kOkRC ) + return rc; + + lib_t* p = mem::allocZ(); + + h.set(p); + + return rc; +} + +cw::rc_t cw::lib::finalize( handle_t& h ) +{ + rc_t rc = kOkRC; + if( !h.isValid() ) + return rc; + + lib_t* p = _handleToPtr(h); + if((rc = _finalize(p)) != kOkRC ) + return rc; + + h.clear(); + + return rc; +} + +cw::rc_t cw::lib::open( handle_t h, const char* fn, unsigned& libIdRef ) +{ + rc_t rc = kOkRC; + lib_t* p = _handleToPtr(h); + dynLibH_t lH = _cmLibOpen(fn); + node_t* np = p->list; + unsigned idx = 0; + + libIdRef = kInvalidId; + + if( _cmLibIsNull(lH) ) + { + // There is apparently no way to get an error code which indicates that the + // file load attempt failed because the file was not a shared library - + // which should not generate an error message - therefore + // we must match the end of the the error string returned by dlerror() with + // 'invalid ELF header'. + const char* errMsg = _cmLibSysError(); + const char* s = "invalid ELF header"; + unsigned sn = strlen(s); + unsigned mn = strlen(errMsg); + + // Did this load fail because the file was not a shared library? + if( errMsg!=nullptr && mn>sn && strcmp(errMsg+mn-sn,s)==0 ) + rc = cwLogError(kOpenFailRC,"Library load failed. No error message." ); // signal error but no error message + else + rc = cwLogError(kOpenFailRC,"Library load failed. System Message: %s", errMsg ); + + return rc; + } + + // find an available node + while( np != nullptr ) + { + if( np->fn == nullptr ) + break; + + np = np->link; + ++idx; + } + + // no available node was found - allocate a new one + if( np == nullptr ) + { + np = mem::allocZ(1); + np->link = p->list; + p->list = np; + } + + // initialize the node + np->fn = mem::duplStr(fn); + np->dynLibH = lH; + np->id = p->id++; + libIdRef = np->id; + + return idx; +} + +cw::rc_t cw::lib::close( handle_t h, unsigned libId ) +{ + lib_t* p = _handleToPtr(h); + node_t* np; + + // locate the library to close + if((np = _libIdToNode(p,libId)) == nullptr ) + return cwLogError(kInvalidIdRC,"Library close failed. The library with id:%i not found.",libId); + + return _closeLib(np); +} + +void* cw::lib::symbol( handle_t h, unsigned libId, const char* symName ) +{ + void* f; + lib_t* p = _handleToPtr(h); + node_t* np = _libIdToNode(p,libId); + + if( (np == NULL) || _cmLibIsNull(np->dynLibH) ) + { + cwLogError(kInvalidArgRC,"The library id %i is not valid or the library is closed.",libId); + return NULL; + } + + if((f = _cmLibSym(np->dynLibH,symName)) == NULL) + { + cwLogError(kInvalidArgRC,"The dynamic symbol '%s' was not found. System Message: %s", cwStringNullGuard(symName), _cmLibSysError()); + return NULL; + } + + return f; +} + +cw::rc_t cw::lib::scan( handle_t h, const char* dirStr ) +{ + rc_t rc = kOkRC; + unsigned dirEntryN = 0; + filesys::dirEntry_t* de = dirEntries( dirStr, filesys::kFileFsFl, &dirEntryN ); + unsigned libId; + + for(unsigned i=0; ilist; + for(; np!=nullptr; np=np->link) + ++n; + return n; +} + +unsigned cw::lib::indexToId( handle_t h, unsigned idx ) +{ + lib_t* p = _handleToPtr(h); + unsigned n = 0; + node_t* np = p->list; + + for(; np!=nullptr; np=np->link) + if( n == idx ) + return np->id; + + cwLogError(kInvalidArgRC, "The library index %i is not valid.",idx); + return kInvalidId; +} + + +const char* cw::lib::name( handle_t h, unsigned id ) +{ + lib_t* p = _handleToPtr(h); + node_t* np; + if((np = _libIdToNode(p,id)) == nullptr ) + { + cwLogError(kInvalidArgRC,"The library associated with the the id:%i could not be found.",id); + return nullptr; + } + return np->fn; +} diff --git a/cwLib.h b/cwLib.h new file mode 100644 index 0000000..4c53708 --- /dev/null +++ b/cwLib.h @@ -0,0 +1,31 @@ +#ifndef cwLib_H +#define cwLib_H + + +namespace cw +{ + namespace lib + { + typedef handle handle_t; + + rc_t initialize( handle_t& h, const char* dirStr ); + rc_t finalize( handle_t& h ); + // libIdRef is set to kInvalidId if rc != kOkRC + rc_t open( handle_t h, const char* fn, unsigned& libIdRef ); + rc_t close( handle_t h, unsigned libId ); + void* symbol( handle_t h, unsigned libId, const char* symName ); + + // open all the libraries in a directory + rc_t scan( handle_t h, const char* dir ); + + // Return the count of open libraries, + unsigned count(handle_t h ); + unsigned indexToId( handle_t h, unsigned idx ); + + // Return the name associated with the i'th library + const char* name( handle_t h, unsigned id ); + } +} + + +#endif diff --git a/cwMutex.cpp b/cwMutex.cpp new file mode 100644 index 0000000..96c3aa4 --- /dev/null +++ b/cwMutex.cpp @@ -0,0 +1,157 @@ +#include "cwCommon.h" +#include "cwLog.h" +#include "cwCommonImpl.h" +#include "cwMem.h" +#include "cwMutex.h" +#include "cwTime.h" + +#include + +namespace cw +{ + namespace mutex + { + typedef struct mutex_str + { + pthread_mutex_t mutex; + pthread_cond_t cvar; + } mutex_t; + + + mutex_t* _handleToPtr( handle_t h ) + { return handleToPtr(h); } + + rc_t _destroy( mutex_t* p ) + { + rc_t rc = kOkRC; + int sysRC; + + if((sysRC = pthread_cond_destroy(&p->cvar)) != 0) + cwLogSysError(kObjFreeFailRC,sysRC,"Thread condition var. destroy failed."); + else + if((sysRC = pthread_mutex_destroy(&p->mutex)) != 0) + cwLogSysError(kObjFreeFailRC,sysRC,"Thread mutex destroy failed."); + else + mem::release(p); + + return rc; + } + } +} + +cw::rc_t cw::mutex::create( handle_t& h ) +{ + rc_t rc; + if((rc = destroy(h)) != kOkRC ) + return rc; + + mutex_t* p = mem::allocZ(); + int sysRC; + + if((sysRC = pthread_mutex_init(&p->mutex,NULL)) != 0 ) + cwLogSysError(kObjAllocFailRC,sysRC,"Thread mutex create failed."); + else + if((sysRC = pthread_cond_init(&p->cvar,NULL)) != 0 ) + cwLogSysError(kObjAllocFailRC,sysRC,"Thread Condition var. create failed."); + + return rc; +} + +cw::rc_t cw::mutex::destroy( handle_t& h ) +{ + rc_t rc = kOkRC; + if( !h.isValid() ) + return rc; + + mutex_t* p = _handleToPtr(h); + if((rc = _destroy(p)) != kOkRC ) + return rc; + + h.clear(); + + return rc; +} + +cw::rc_t cw::mutex::tryLock( handle_t h, bool& lockFlRef ) +{ + rc_t rc = kOkRC; + mutex_t* p = _handleToPtr(h); + int sysRc = pthread_mutex_trylock(&p->mutex); + + switch(sysRc) + { + case EBUSY: + lockFlRef = false; + break; + + case 0: + lockFlRef = true; + break; + + default: + rc = cwLogSysError(kInvalidOpRC,sysRc,"Thread mutex try-lock failed."); + } + + return rc; +} + +cw::rc_t cw::mutex::lock( handle_t h ) +{ + rc_t rc = kOkRC; + mutex_t* p = _handleToPtr(h); + int sysRc; + + if((sysRc = pthread_mutex_lock(&p->mutex)) != 0) + rc = cwLogSysError(kInvalidOpRC,sysRc,"Lock failed."); + + return rc; +} + +cw::rc_t cw::mutex::unlock( handle_t h ) +{ + rc_t rc = kOkRC; + mutex_t* p = _handleToPtr(h); + int sysRc; + + if((sysRc = pthread_mutex_unlock(&p->mutex)) != 0) + return cwLogSysError(kInvalidOpRC,sysRc,"Unlock failed."); + + return rc; +} + +cw::rc_t cw::mutex::waitOnCondVar( handle_t h, bool lockThenWaitFl, unsigned timeOutMs ) +{ + rc_t rc = kOkRC; + mutex_t* p = _handleToPtr(h); + int sysRC; + + if( lockThenWaitFl ) + if((sysRC = pthread_mutex_lock(&p->mutex)) != 0) + return cwLogSysError(kInvalidOpRC,sysRC,"Lock failed."); + + // if no timeout was given .... + if( timeOutMs == 0) + { + // ... then wait until the cond-var is triggered + if((sysRC = pthread_cond_wait(&p->cvar,&p->mutex)) != 0 ) + return cwLogSysError(kInvalidOpRC,sysRC,"Thread cond. var. wait failed."); + } + else // ... otherwise use the cond. var. wait with timeout API + { + + struct timespec ts; + + if((rc = time::futureMs(ts,timeOutMs)) == kOkRC ) + if((sysRC = pthread_cond_timedwait(&p->cvar,&p->mutex,&ts)) != 0 ) + { + if( sysRC == ETIMEDOUT ) + rc = kTimeOutRC; + else + return cwLogSysError(kInvalidOpRC,sysRC,"Thread cond. var. wait failed."); + } + } + + return rc; + + +} diff --git a/cwMutex.h b/cwMutex.h new file mode 100644 index 0000000..f1cdf76 --- /dev/null +++ b/cwMutex.h @@ -0,0 +1,24 @@ +#ifndef cwMutex_H +#define cwMutex_H + +namespace cw +{ + namespace mutex + { + typedef handle handle_t; + + rc_t create( handle_t& h ); + rc_t destroy( handle_t& h ); + + rc_t tryLock( handle_t h, bool& lockFlRef ); + rc_t lock( handle_t h ); + rc_t unlock( handle_t h ); + + rc_t waitOnCondVar( handle_t h, bool lockThenWaitFl, unsigned timeOutMs ); + + } +} + + + +#endif