From 1d6be74ee5399b9ee73eaa77cc2ec17ef706d939 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Fri, 29 Nov 2019 10:29:36 +0100 Subject: [PATCH 1/4] rxr: removed return ok or fail and replaced with exceptions --- slsReceiverSoftware/include/BinaryFile.h | 9 +- .../include/BinaryFileStatic.h | 35 +- slsReceiverSoftware/include/DataProcessor.h | 12 +- slsReceiverSoftware/include/DataStreamer.h | 6 +- slsReceiverSoftware/include/Fifo.h | 3 +- slsReceiverSoftware/include/File.h | 9 +- slsReceiverSoftware/include/HDF5File.h | 15 +- slsReceiverSoftware/include/HDF5FileStatic.h | 519 ++++++++---------- slsReceiverSoftware/include/Implementation.h | 52 +- slsReceiverSoftware/include/Listener.h | 9 +- slsReceiverSoftware/include/ThreadObject.h | 3 +- slsReceiverSoftware/src/BinaryFile.cpp | 17 +- slsReceiverSoftware/src/ClientInterface.cpp | 109 ++-- slsReceiverSoftware/src/DataProcessor.cpp | 47 +- slsReceiverSoftware/src/DataStreamer.cpp | 22 +- slsReceiverSoftware/src/Fifo.cpp | 9 +- slsReceiverSoftware/src/HDF5File.cpp | 78 +-- slsReceiverSoftware/src/Implementation.cpp | 195 ++----- slsReceiverSoftware/src/Listener.cpp | 32 +- slsReceiverSoftware/src/ThreadObject.cpp | 14 +- 20 files changed, 517 insertions(+), 678 deletions(-) diff --git a/slsReceiverSoftware/include/BinaryFile.h b/slsReceiverSoftware/include/BinaryFile.h index 2b3535bbf..a5337bbaf 100755 --- a/slsReceiverSoftware/include/BinaryFile.h +++ b/slsReceiverSoftware/include/BinaryFile.h @@ -51,17 +51,15 @@ class BinaryFile : private virtual slsDetectorDefs, public File, public BinaryFi /** * Create file - * @returns OK or FAIL */ - int CreateFile() override; + void CreateFile() override; /** * Create master file * @param mfwenable master file write enable * @param attr master file attributes - * @returns OK or FAIL */ - int CreateMasterFile(bool mfwenable, masterAttributes& attr) override; + void CreateMasterFile(bool mfwenable, masterAttributes& attr) override; /** * Close Current File @@ -79,9 +77,8 @@ class BinaryFile : private virtual slsDetectorDefs, public File, public BinaryFi * @param buffersize size of buffer * @param fnum current image number * @param nump number of packets caught - * @returns OK or FAIL */ - int WriteToFile(char* buffer, int buffersize, uint64_t fnum, uint32_t nump) override; + void WriteToFile(char* buffer, int buffersize, uint64_t fnum, uint32_t nump) override; diff --git a/slsReceiverSoftware/include/BinaryFileStatic.h b/slsReceiverSoftware/include/BinaryFileStatic.h index 29483adef..032aeed30 100755 --- a/slsReceiverSoftware/include/BinaryFileStatic.h +++ b/slsReceiverSoftware/include/BinaryFileStatic.h @@ -98,23 +98,20 @@ class BinaryFileStatic { * @param fname master file name * @param owenable overwrite enable * @param attr master file attributes - * @returns 0 for success and 1 for fail */ - static int CreateMasterDataFile(FILE*& fd, std::string fname, bool owenable, + static void CreateMasterDataFile(FILE*& fd, std::string fname, bool owenable, masterAttributes& attr) { if(!owenable){ if (NULL == (fd = fopen((const char *) fname.c_str(), "wx"))){ - FILE_LOG(logERROR) << "Could not create binary master file " - "(without overwrite enable) " << fname; fd = 0; - return 1; + throw sls::RuntimeError("Could not create binary master file " + "(without overwrite enable) " + fname); } }else if (NULL == (fd = fopen((const char *) fname.c_str(), "w"))){ - FILE_LOG(logERROR) << "Could not create binary master file " - "(with overwrite enable) " << fname; fd = 0; - return 1; + throw sls::RuntimeError("Could not create binary master file " + "(with overwrite enable) " + fname); } time_t t = time(0); char message[MAX_MASTER_FILE_LENGTH]; @@ -182,16 +179,15 @@ class BinaryFileStatic { attr.roiXmax, ctime(&t)); if (strlen(message) > MAX_MASTER_FILE_LENGTH) { - FILE_LOG(logERROR) << "Master File Size " << strlen(message) << - " is greater than max str size " << MAX_MASTER_FILE_LENGTH; - return 1; + throw sls::RuntimeError("Master File Size " + std::to_string(strlen(message)) + + " is greater than max str size " + std::to_string(MAX_MASTER_FILE_LENGTH)); } - if (fwrite((void*)message, 1, strlen(message), fd) != strlen(message)) - return 1; + if (fwrite((void*)message, 1, strlen(message), fd) != strlen(message)) { + throw sls::RuntimeError("Master binary file incorrect number of bytes written to file"); + } BinaryFileStatic::CloseDataFile(fd); - return 0; } @@ -203,22 +199,19 @@ class BinaryFileStatic { * @param filebuffersize file buffer size * @returns 0 for success and 1 for fail */ - static int CreateDataFile(FILE*& fd, bool owenable, std::string fname, size_t filebuffersize) + static void CreateDataFile(FILE*& fd, bool owenable, std::string fname, size_t filebuffersize) { if(!owenable){ if (NULL == (fd = fopen((const char *) fname.c_str(), "wx"))){ - FILE_LOG(logERROR) << "Could not create/overwrite file" << fname; fd = 0; - return 1; + throw sls::RuntimeError("Could not create/overwrite file " + fname); } - }else if (NULL == (fd = fopen((const char *) fname.c_str(), "w"))){ - FILE_LOG(logERROR) << "Could not create file" << fname; + } else if (NULL == (fd = fopen((const char *) fname.c_str(), "w"))){ fd = 0; - return 1; + throw sls::RuntimeError("Could not create file " + fname); } //setting file buffer size to 16mb setvbuf(fd,NULL,_IOFBF,filebuffersize); - return 0; } }; diff --git a/slsReceiverSoftware/include/DataProcessor.h b/slsReceiverSoftware/include/DataProcessor.h index 893c74466..ff0a430e8 100755 --- a/slsReceiverSoftware/include/DataProcessor.h +++ b/slsReceiverSoftware/include/DataProcessor.h @@ -121,9 +121,8 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { /** * Set thread priority * @priority priority - * @returns OK or FAIL */ - int SetThreadPriority(int priority); + void SetThreadPriority(int priority); /** * Set File Format @@ -155,9 +154,8 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { /** * Create New File * @param attr master file attributes - * @returns OK or FAIL */ - int CreateNewFile(masterAttributes& attr); + void CreateNewFile(masterAttributes& attr); /** * Closes files @@ -213,12 +211,6 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { */ void RecordFirstIndex(uint64_t fnum); - /** - * Destroy file writer object - * @return OK or FAIL - */ - void DestroyFileWriter(); - /** * Thread Exeution for DataProcessor Class * Pop bound addresses, process them, diff --git a/slsReceiverSoftware/include/DataStreamer.h b/slsReceiverSoftware/include/DataStreamer.h index 59a68ea22..f341fa960 100755 --- a/slsReceiverSoftware/include/DataStreamer.h +++ b/slsReceiverSoftware/include/DataStreamer.h @@ -82,9 +82,8 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject { /** * Set thread priority * @priority priority - * @returns OK or FAIL */ - int SetThreadPriority(int priority); + void SetThreadPriority(int priority); /** * Set number of detectors @@ -114,9 +113,8 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject { /** * Restream stop dummy packet - * @return OK or FAIL */ - int RestreamStop(); + void RestreamStop(); private: diff --git a/slsReceiverSoftware/include/Fifo.h b/slsReceiverSoftware/include/Fifo.h index 082357168..7167ce4aa 100755 --- a/slsReceiverSoftware/include/Fifo.h +++ b/slsReceiverSoftware/include/Fifo.h @@ -78,9 +78,8 @@ class Fifo : private virtual slsDetectorDefs { /** * Create Fifos, allocate memory & push addresses into fifo * @param fifoItemSize size of each fifo item - * @return OK if successful, else FAIL */ - int CreateFifos(uint32_t fifoItemSize); + void CreateFifos(uint32_t fifoItemSize); /** * Destroy Fifos and deallocate memory diff --git a/slsReceiverSoftware/include/File.h b/slsReceiverSoftware/include/File.h index 7d11dd77b..67f047ecb 100755 --- a/slsReceiverSoftware/include/File.h +++ b/slsReceiverSoftware/include/File.h @@ -84,9 +84,8 @@ class File : private virtual slsDetectorDefs { /** * Create file - * @returns OK or FAIL */ - virtual int CreateFile() = 0; + virtual void CreateFile() = 0; /** * Close Current File @@ -103,17 +102,15 @@ class File : private virtual slsDetectorDefs { * @param buffer buffer to write from * @param fnum current image number * @param nump number of packets caught - * @param OK or FAIL */ - virtual int WriteToFile(char* buffer, int buffersize, uint64_t fnum, uint32_t nump) = 0; + virtual void WriteToFile(char* buffer, int buffersize, uint64_t fnum, uint32_t nump) = 0; /** * Create master file * @param mfwenable master file write enable * @param attr master file attributes - * @returns OK or FAIL */ - virtual int CreateMasterFile(bool mfwenable, masterAttributes& attr) = 0; + virtual void CreateMasterFile(bool mfwenable, masterAttributes& attr) = 0; // HDf5 specific /** diff --git a/slsReceiverSoftware/include/HDF5File.h b/slsReceiverSoftware/include/HDF5File.h index 65bfba2eb..5706ec126 100755 --- a/slsReceiverSoftware/include/HDF5File.h +++ b/slsReceiverSoftware/include/HDF5File.h @@ -67,9 +67,8 @@ class HDF5File : private virtual slsDetectorDefs, public File, public HDF5FileSt /** * Create file * @param fnum current frame index to include in file name - * @returns OK or FAIL */ - int CreateFile(); + void CreateFile(); /** * Close Current File @@ -87,17 +86,15 @@ class HDF5File : private virtual slsDetectorDefs, public File, public HDF5FileSt * @param bsize size of buffer (not used) * @param fnum current image number * @param nump number of packets caught - * @returns OK or FAIL */ - int WriteToFile(char* buffer, int bsize, uint64_t fnum, uint32_t nump); + void WriteToFile(char* buffer, int bsize, uint64_t fnum, uint32_t nump); /** * Create master file * @param mfwenable master file write enable * @param attr master file attributes - * @returns OK or FAIL */ - int CreateMasterFile(bool mfwenable, masterAttributes& attr); + void CreateMasterFile(bool mfwenable, masterAttributes& attr); /** * End of Acquisition @@ -112,16 +109,14 @@ class HDF5File : private virtual slsDetectorDefs, public File, public HDF5FileSt /** * Create Virtual File * @param numf number of images caught - * @returns OK or FAIL */ - int CreateVirtualFile(uint64_t numf); + void CreateVirtualFile(uint64_t numf); /** * Link virtual file in master file * Only for Jungfrau at the moment for 1 module and 1 data file - * @returns OK or FAIL */ - int LinkVirtualFileinMasterFile(); + void LinkVirtualFileinMasterFile(); /** * Get Type diff --git a/slsReceiverSoftware/include/HDF5FileStatic.h b/slsReceiverSoftware/include/HDF5FileStatic.h index 2cdc0a810..4d2600d8e 100755 --- a/slsReceiverSoftware/include/HDF5FileStatic.h +++ b/slsReceiverSoftware/include/HDF5FileStatic.h @@ -156,9 +156,8 @@ public: * @param dspace dataspace pointer * @param dset dataset pointer * @param dtype datatype - * @returns 0 for success and 1 for fail */ - static int WriteDataFile(int ind, char* buf, + static void WriteDataFile(int ind, char* buf, uint64_t nDimx, uint32_t nDimy, uint32_t nDimz, DataSpace* dspace, DataSet* dset, DataType dtype) { @@ -176,9 +175,8 @@ public: catch(const Exception& error){ FILE_LOG(logERROR) << "Could not write to file in object " << ind; error.printErrorStack(); - return 1; + throw RuntimeError("Could not write to file in object " + std::to_string(ind)); } - return 0; } @@ -192,7 +190,7 @@ public: * @param rheader sls_receiver_header pointer * @param parameterDataTypes parameter datatypes */ - static int WriteParameterDatasets(int ind, DataSpace* dspace_para, uint64_t fnum, + static void WriteParameterDatasets(int ind, DataSpace* dspace_para, uint64_t fnum, std::vector dset_para,sls_receiver_header* rheader, std::vector parameterDataTypes) { @@ -236,11 +234,9 @@ public: }i=14; } catch(const Exception& error){ - FILE_LOG(logERROR) << "Could not write parameters (index:" << i << ") to file in object " << ind; error.printErrorStack(); - return 1; + throw RuntimeError("Could not write parameters (index:" + std::to_string(i) + ") to file in object " + std::to_string(ind)); } - return 0; } @@ -253,9 +249,8 @@ public: * @param dspace_para parameter dataspace address pointer * @param dset dataset parameter pointer * @param initialNumImages initial number of images - * @returns 0 for success and 1 for fail */ - static int ExtendDataset(int ind, DataSpace*& dspace, DataSet* dset, + static void ExtendDataset(int ind, DataSpace*& dspace, DataSet* dset, DataSpace*& dspace_para, std::vector dset_para, uint64_t initialNumImages) { try{ @@ -279,11 +274,9 @@ public: } catch(const Exception& error){ - FILE_LOG(logERROR) << "Could not extend dataset in object " << ind; error.printErrorStack(); - return 1; + throw RuntimeError("Could not extend dataset in object " + std::to_string(ind)); } - return 0; } @@ -292,9 +285,8 @@ public: * @param fname master file name * @param owenable overwrite enable * @param attr master file attributes - * @returns 0 for success and 1 for fail */ - static int CreateMasterDataFile(H5File*& fd, std::string fname, bool owenable, + static void CreateMasterDataFile(H5File*& fd, std::string fname, bool owenable, masterAttributes& attr) { try { @@ -443,12 +435,10 @@ public: fd->close(); } catch(const Exception& error) { - FILE_LOG(logERROR) << "Could not create master HDF5 handles"; error.printErrorStack(); if (fd) fd->close(); - return 1; + throw RuntimeError("Could not create master HDF5 handles"); } - return 0; } @@ -473,9 +463,8 @@ public: * @param dset_para vector of datasets of parameters * @param parameterNames parameter names * @param parameterDataTypes parameter datatypes - * @returns 0 for success and 1 for fail */ - static int CreateDataFile(int ind, bool owenable, std::string fname, bool frindexenable, + static void CreateDataFile(int ind, bool owenable, std::string fname, bool frindexenable, uint64_t fnum, uint64_t nDimx, uint32_t nDimy, uint32_t nDimz, DataType dtype, H5File*& fd, DataSpace*& dspace, DataSet*& dset, double version, uint64_t maxchunkedimages, @@ -547,12 +536,10 @@ public: } } catch(const Exception& error){ - FILE_LOG(logERROR) << "Could not create HDF5 handles in object " << ind; error.printErrorStack(); if (fd) fd->close(); - return 1; + throw RuntimeError("Could not create HDF5 handles in object " + ind); } - return 0; } @@ -579,9 +566,8 @@ public: * @param version version of software for hdf5 writing * @param parameterNames parameter names * @param parameterDataTypes parameter datatypes - * @returns 0 for success and 1 for fail */ - static int CreateVirtualDataFile( + static void CreateVirtualDataFile( std::string virtualFileName, hid_t& fd, std::string masterFileName, std::string fpath, std::string fnameprefix, uint64_t findex, bool frindexenable, @@ -593,206 +579,167 @@ public: std::vector parameterNames, std::vector parameterDataTypes) { - //file - hid_t dfal = H5Pcreate (H5P_FILE_ACCESS); - if (dfal < 0) - return CloseFileOnError(fd, - std::string("Could not create file access property for virtual file ") - + virtualFileName + std::string("\n")); - if (H5Pset_fclose_degree (dfal, H5F_CLOSE_STRONG) < 0) - return CloseFileOnError(fd, - std::string("Could not set strong file close degree for virtual file ") - + virtualFileName + std::string("\n")); - fd = H5Fcreate( virtualFileName.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, dfal); - if (fd < 0) - return CloseFileOnError(fd, - std::string("Could not create virtual file ") + virtualFileName + std::string("\n")); + try { + //file + hid_t dfal = H5Pcreate (H5P_FILE_ACCESS); + if (dfal < 0) + throw RuntimeError("Could not create file access property for virtual file " + virtualFileName); + if (H5Pset_fclose_degree (dfal, H5F_CLOSE_STRONG) < 0) + throw RuntimeError("Could not set strong file close degree for virtual file " + virtualFileName); + fd = H5Fcreate( virtualFileName.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, dfal); + if (fd < 0) + throw RuntimeError("Could not create virtual file " + virtualFileName); - //attributes - version - hid_t dataspace_attr = H5Screate (H5S_SCALAR); - if (dataspace_attr < 0) - return CloseFileOnError(fd, - std::string("Could not create dataspace for attribute in virtual file ") - + virtualFileName + std::string("\n")); - hid_t attrid = H5Acreate2 (fd, "version", H5T_NATIVE_DOUBLE, dataspace_attr, H5P_DEFAULT, H5P_DEFAULT); - if (attrid < 0) - return CloseFileOnError(fd, - std::string("Could not create attribute in virtual file ") - + virtualFileName + std::string("\n")); - double attr_data = version; - if (H5Awrite (attrid, H5T_NATIVE_DOUBLE, &attr_data) < 0) - return CloseFileOnError(fd, - std::string("Could not write attribute in virtual file ") - + virtualFileName + std::string("\n")); - if (H5Aclose (attrid) < 0) - return CloseFileOnError(fd, - std::string("Could not close attribute in virtual file ") - + virtualFileName + std::string("\n")); + //attributes - version + hid_t dataspace_attr = H5Screate (H5S_SCALAR); + if (dataspace_attr < 0) + throw RuntimeError("Could not create dataspace for attribute in virtual file " + virtualFileName); + hid_t attrid = H5Acreate2 (fd, "version", H5T_NATIVE_DOUBLE, dataspace_attr, H5P_DEFAULT, H5P_DEFAULT); + if (attrid < 0) + throw RuntimeError("Could not create attribute in virtual file " + virtualFileName); + double attr_data = version; + if (H5Awrite (attrid, H5T_NATIVE_DOUBLE, &attr_data) < 0) + throw RuntimeError("Could not write attribute in virtual file " + virtualFileName); + if (H5Aclose (attrid) < 0) + throw RuntimeError("Could not close attribute in virtual file " + virtualFileName); - //virtual dataspace - hsize_t vdsdims[3] = {numf, numDety * nDimy, numDetz * nDimz}; - hid_t vdsDataspace = H5Screate_simple(3, vdsdims ,NULL); - if (vdsDataspace < 0) - return CloseFileOnError(fd, - std::string("Could not create virtual dataspace in virtual file ") - + virtualFileName + std::string("\n")); - hsize_t vdsdims_para[2] = {numf, (unsigned int) numDety * numDetz}; - hid_t vdsDataspace_para = H5Screate_simple(2, vdsdims_para, NULL); - if (vdsDataspace_para < 0) - return CloseFileOnError(fd, - std::string("Could not create virtual dataspace (parameters) in virtual file ") - + virtualFileName + std::string("\n")); + //virtual dataspace + hsize_t vdsdims[3] = {numf, numDety * nDimy, numDetz * nDimz}; + hid_t vdsDataspace = H5Screate_simple(3, vdsdims ,NULL); + if (vdsDataspace < 0) + throw RuntimeError("Could not create virtual dataspace in virtual file " + virtualFileName); + hsize_t vdsdims_para[2] = {numf, (unsigned int) numDety * numDetz}; + hid_t vdsDataspace_para = H5Screate_simple(2, vdsdims_para, NULL); + if (vdsDataspace_para < 0) + throw RuntimeError("Could not create virtual dataspace (parameters) in virtual file " + virtualFileName); - //fill values - hid_t dcpl = H5Pcreate (H5P_DATASET_CREATE); - if (dcpl < 0) - return CloseFileOnError(fd, - std::string("Could not create file creation properties in virtual file ") - + virtualFileName + std::string("\n")); - int fill_value = -1; - if (H5Pset_fill_value (dcpl, GetDataTypeinC(dataType), &fill_value) < 0) - return CloseFileOnError(fd, - std::string("Could not create fill value in virtual file ") - + virtualFileName + std::string("\n")); - hid_t dcpl_para[parameterNames.size()]; - for (unsigned int i = 0; i < parameterNames.size(); ++i) { - dcpl_para[i] = H5Pcreate (H5P_DATASET_CREATE); - if (dcpl_para[i] < 0) - return CloseFileOnError(fd, - std::string("Could not create file creation properties (parameters) in virtual file ") - + virtualFileName + std::string("\n")); - if (H5Pset_fill_value (dcpl_para[i], GetDataTypeinC(parameterDataTypes[i]), &fill_value) < 0) - return CloseFileOnError(fd, - std::string("Could not create fill value (parameters) in virtual file ") - + virtualFileName + std::string("\n")); - } - - //hyperslab - int numMajorHyperslab = numf/maxFramesPerFile; - if (numf%maxFramesPerFile) numMajorHyperslab++; - bool error = false; - uint64_t framesSaved = 0; - for (int j = 0; j < numMajorHyperslab; j++) { - - uint64_t nDimx = ((numf - framesSaved) > maxFramesPerFile) - ? maxFramesPerFile : (numf-framesSaved); - hsize_t offset[3] = {framesSaved, 0, 0}; - hsize_t count[3] = {nDimx, nDimy, nDimz}; - hsize_t offset_para[2] = {framesSaved, 0}; - hsize_t count_para[2] = {nDimx, 1}; - - for (int i = 0; i < numDety * numDetz; ++i) { - - //setect hyperslabs - if (H5Sselect_hyperslab (vdsDataspace, H5S_SELECT_SET, offset, NULL, count, NULL) < 0) { - FILE_LOG(logERROR) << "Could not select hyperslab"; - error = true; - break; - } - if (H5Sselect_hyperslab (vdsDataspace_para, H5S_SELECT_SET, - offset_para, NULL, count_para, NULL) < 0) { - FILE_LOG(logERROR) << "Could not select hyperslab for parameters"; - error = true; - break; - } - - //source file name - std::string srcFileName = HDF5FileStatic::CreateFileName(fpath, fnameprefix, findex, - j, dindex, numunits, i); - - FILE_LOG(logERROR) << srcFileName; - // find relative path - std::string relative_srcFileName = srcFileName; - { - size_t i = srcFileName.rfind('/', srcFileName.length()); - if (i != std::string::npos) - relative_srcFileName = (srcFileName.substr(i+1, srcFileName.length() - i)); - } - - //source dataset name - std::ostringstream osfn; - osfn << "/data"; - if (frindexenable) osfn << "_f" << std::setfill('0') << std::setw(12) << j; - std::string srcDatasetName = osfn.str(); - - //source dataspace - hsize_t srcdims[3] = {nDimx, nDimy, nDimz}; - hsize_t srcdimsmax[3] = {H5S_UNLIMITED, nDimy, nDimz}; - hid_t srcDataspace = H5Screate_simple(3, srcdims, srcdimsmax); - if (srcDataspace < 0) - return CloseFileOnError(fd, - std::string("Could not create source dataspace in virtual file ") - + virtualFileName + std::string("\n")); - hsize_t srcdims_para[1] = {nDimx}; - hsize_t srcdimsmax_para[1] = {H5S_UNLIMITED}; - hid_t srcDataspace_para = H5Screate_simple(1, srcdims_para, srcdimsmax_para); - if (srcDataspace_para < 0) - return CloseFileOnError(fd, - std::string("Could not create source dataspace (parameters) in virtual file ") - + virtualFileName + std::string("\n")); - - //mapping - if (H5Pset_virtual(dcpl, vdsDataspace, relative_srcFileName.c_str(), - srcDatasetName.c_str(), srcDataspace) < 0) { - FILE_LOG(logERROR) << "Could not set mapping for paramter 1"; - error = true; - break; - } - - for (unsigned int k = 0; k < parameterNames.size(); ++k) { - if (H5Pset_virtual(dcpl_para[k], vdsDataspace_para, relative_srcFileName.c_str(), - parameterNames[k], srcDataspace_para) < 0) { - FILE_LOG(logERROR) << "Could not set mapping for paramter " << k; - error = true; - break; - } - } - - //H5Sclose(srcDataspace); - //H5Sclose(srcDataspace_para); - offset[2] += nDimz; - if (offset[2] >= (numDetz * nDimz)) { - offset[2] = 0; - offset[1] += nDimy; - } - offset_para[1]++; + //fill values + hid_t dcpl = H5Pcreate (H5P_DATASET_CREATE); + if (dcpl < 0) + throw RuntimeError("Could not create file creation properties in virtual file " + virtualFileName); + int fill_value = -1; + if (H5Pset_fill_value (dcpl, GetDataTypeinC(dataType), &fill_value) < 0) + throw RuntimeError("Could not create fill value in virtual file " + virtualFileName); + hid_t dcpl_para[parameterNames.size()]; + for (unsigned int i = 0; i < parameterNames.size(); ++i) { + dcpl_para[i] = H5Pcreate (H5P_DATASET_CREATE); + if (dcpl_para[i] < 0) + throw RuntimeError("Could not create file creation properties (parameters) in virtual file " + virtualFileName); + if (H5Pset_fill_value (dcpl_para[i], GetDataTypeinC(parameterDataTypes[i]), &fill_value) < 0) + throw RuntimeError("Could not create fill value (parameters) in virtual file " + virtualFileName); } - framesSaved += nDimx; + + //hyperslab + int numMajorHyperslab = numf/maxFramesPerFile; + if (numf%maxFramesPerFile) numMajorHyperslab++; + uint64_t framesSaved = 0; + for (int j = 0; j < numMajorHyperslab; j++) { + + uint64_t nDimx = ((numf - framesSaved) > maxFramesPerFile) + ? maxFramesPerFile : (numf-framesSaved); + hsize_t offset[3] = {framesSaved, 0, 0}; + hsize_t count[3] = {nDimx, nDimy, nDimz}; + hsize_t offset_para[2] = {framesSaved, 0}; + hsize_t count_para[2] = {nDimx, 1}; + + for (int i = 0; i < numDety * numDetz; ++i) { + + //setect hyperslabs + if (H5Sselect_hyperslab (vdsDataspace, H5S_SELECT_SET, offset, NULL, count, NULL) < 0) { + throw RuntimeError("Could not select hyperslab"); + } + if (H5Sselect_hyperslab (vdsDataspace_para, H5S_SELECT_SET, + offset_para, NULL, count_para, NULL) < 0) { + throw RuntimeError("Could not select hyperslab for parameters"); + } + + //source file name + std::string srcFileName = HDF5FileStatic::CreateFileName(fpath, fnameprefix, findex, + j, dindex, numunits, i); + + FILE_LOG(logERROR) << srcFileName; + // find relative path + std::string relative_srcFileName = srcFileName; + { + size_t i = srcFileName.rfind('/', srcFileName.length()); + if (i != std::string::npos) + relative_srcFileName = (srcFileName.substr(i+1, srcFileName.length() - i)); + } + + //source dataset name + std::ostringstream osfn; + osfn << "/data"; + if (frindexenable) osfn << "_f" << std::setfill('0') << std::setw(12) << j; + std::string srcDatasetName = osfn.str(); + + //source dataspace + hsize_t srcdims[3] = {nDimx, nDimy, nDimz}; + hsize_t srcdimsmax[3] = {H5S_UNLIMITED, nDimy, nDimz}; + hid_t srcDataspace = H5Screate_simple(3, srcdims, srcdimsmax); + if (srcDataspace < 0) + throw RuntimeError("Could not create source dataspace in virtual file " + virtualFileName); + hsize_t srcdims_para[1] = {nDimx}; + hsize_t srcdimsmax_para[1] = {H5S_UNLIMITED}; + hid_t srcDataspace_para = H5Screate_simple(1, srcdims_para, srcdimsmax_para); + if (srcDataspace_para < 0) + throw RuntimeError("Could not create source dataspace (parameters) in virtual file " + virtualFileName); + + //mapping + if (H5Pset_virtual(dcpl, vdsDataspace, relative_srcFileName.c_str(), + srcDatasetName.c_str(), srcDataspace) < 0) { + throw RuntimeError("Could not set mapping for paramter 1"); + } + + for (unsigned int k = 0; k < parameterNames.size(); ++k) { + if (H5Pset_virtual(dcpl_para[k], vdsDataspace_para, relative_srcFileName.c_str(), + parameterNames[k], srcDataspace_para) < 0) { + throw RuntimeError("Could not set mapping for paramter " + std::to_string(k)); + } + } + + //H5Sclose(srcDataspace); + //H5Sclose(srcDataspace_para); + offset[2] += nDimz; + if (offset[2] >= (numDetz * nDimz)) { + offset[2] = 0; + offset[1] += nDimy; + } + offset_para[1]++; + } + framesSaved += nDimx; + } + + //dataset + std::string virtualDatasetName = srcDataseName; + hid_t vdsdataset = H5Dcreate2 (fd, virtualDatasetName.c_str(), + GetDataTypeinC(dataType), vdsDataspace, H5P_DEFAULT, dcpl, H5P_DEFAULT); + if (vdsdataset < 0) + throw RuntimeError("Could not create virutal dataset in virtual file " + virtualFileName); + + + //virtual parameter dataset + for (unsigned int i = 0; i < parameterNames.size(); ++i) { + hid_t vdsdataset_para = H5Dcreate2 (fd, + parameterNames[i], + GetDataTypeinC(parameterDataTypes[i]), vdsDataspace_para, + H5P_DEFAULT, dcpl_para[i], H5P_DEFAULT); + if (vdsdataset_para < 0) + throw RuntimeError("Could not create virutal dataset (parameters) in virtual file " + virtualFileName); + } + + //close + H5Fclose(fd); + fd = 0; + + //link + LinkVirtualInMaster(masterFileName, virtualFileName, virtualDatasetName, parameterNames); + } catch (const RuntimeError &e) { + if (fd > 0) + H5Fclose(fd); + fd = 0; } - if (error) - return CloseFileOnError(fd, - std::string("Could not map files in virtual file ") - + virtualFileName + std::string("\n")); - - //dataset - std::string virtualDatasetName = srcDataseName; - hid_t vdsdataset = H5Dcreate2 (fd, virtualDatasetName.c_str(), - GetDataTypeinC(dataType), vdsDataspace, H5P_DEFAULT, dcpl, H5P_DEFAULT); - if (vdsdataset < 0) - return CloseFileOnError(fd, - std::string("Could not create virutal dataset in virtual file ") - + virtualFileName + std::string("\n")); - - - //virtual parameter dataset - for (unsigned int i = 0; i < parameterNames.size(); ++i) { - hid_t vdsdataset_para = H5Dcreate2 (fd, - parameterNames[i], - GetDataTypeinC(parameterDataTypes[i]), vdsDataspace_para, - H5P_DEFAULT, dcpl_para[i], H5P_DEFAULT); - if (vdsdataset_para < 0) - return CloseFileOnError(fd, - std::string("Could not create virutal dataset (parameters) in virtual file ") - + virtualFileName + std::string("\n")); - } - - //close - H5Fclose(fd); fd = 0; - - //link - return LinkVirtualInMaster(masterFileName, virtualFileName, virtualDatasetName, parameterNames); } @@ -809,10 +756,9 @@ public: * @param nDimx Number of objects in x dimension * @param nDimy Number of objects in y dimension * @param nDimz Number of objects in z dimension - * @returns 0 for success and 1 for fail */ template - static int CopyVirtualFile(T datatype, bool owenable, std::string oldFileName, std::string oldDatasetName, + static void CopyVirtualFile(T datatype, bool owenable, std::string oldFileName, std::string oldDatasetName, std::string newFileName, std::string newDatasetName, int rank, uint64_t nDimx, uint32_t nDimy, uint32_t nDimz=0) { @@ -825,8 +771,7 @@ public: data_out = (T*)malloc(sizeof(T)*(nDimx*nDimy*nDimz)); break; default: - FILE_LOG(logERROR) << "Invalid rank. Options: 2 or 3"; - return 0; + throw RuntimeError("Invalid rank. Options: 2 or 3"); } if (datatype == PredType::STD_U16LE) { FILE_LOG(logINFO) << "datatype:16"; @@ -837,8 +782,7 @@ public: } else if (datatype == PredType::STD_U8LE) { FILE_LOG(logINFO) << "datatype:8"; } else { - FILE_LOG(logERROR) << "Unknown datatype: " << datatype; - return 1; + throw RuntimeError("Unknown datatype:" + std::to_string(datatype)); } FILE_LOG(logINFO) << "owenable:" << (owenable?1:0) << std::endl << "oldFileName:" << oldFileName << std::endl @@ -888,15 +832,13 @@ public: newfd->close(); oldfd->close(); } catch(const Exception& error){ - FILE_LOG(logERROR) << "Could not copy virtual files"; error.printErrorStack(); free(data_out); oldfd->close(); newfd->close(); - return 1; + throw RuntimeError("Could not copy virtual files"); } free(data_out); - return 0; } @@ -908,89 +850,80 @@ public: * @param virtualfname virtual file name * @param virtualDatasetname virtual dataset name * @param parameterNames parameter names - * @returns 0 for success and 1 for fail */ - static int LinkVirtualInMaster(std::string masterFileName, std::string virtualfname, + static void LinkVirtualInMaster(std::string masterFileName, std::string virtualfname, std::string virtualDatasetname, std::vector parameterNames) { char linkname[100]; hid_t vfd = 0; - hid_t dfal = H5Pcreate (H5P_FILE_ACCESS); - if (dfal < 0) - return CloseFileOnError( vfd, std::string("Could not create file access property for link\n")); - if (H5Pset_fclose_degree (dfal, H5F_CLOSE_STRONG) < 0) - return CloseFileOnError( vfd, std::string("Could not set strong file close degree for link\n")); + try { + hid_t dfal = H5Pcreate (H5P_FILE_ACCESS); + if (dfal < 0) + throw RuntimeError("Could not create file access property for link"); + if (H5Pset_fclose_degree (dfal, H5F_CLOSE_STRONG) < 0) + throw RuntimeError("Could not set strong file close degree for link"); - //open master file - hid_t mfd = H5Fopen( masterFileName.c_str(), H5F_ACC_RDWR, dfal); - if (mfd < 0) - return CloseFileOnError( vfd, std::string("Could not open master file\n")); + //open master file + hid_t mfd = H5Fopen( masterFileName.c_str(), H5F_ACC_RDWR, dfal); + if (mfd < 0) + throw RuntimeError("Could not open master file"); - //open virtual file - vfd = H5Fopen( virtualfname.c_str(), H5F_ACC_RDWR, dfal); - if (vfd < 0) { - H5Fclose(mfd); mfd = 0; - return CloseFileOnError( vfd, std::string("Could not open virtual file\n")); - } - - // find relative path - std::string relative_virtualfname = virtualfname; - { - size_t i = virtualfname.rfind('/', virtualfname.length()); - if (i != std::string::npos) - relative_virtualfname = (virtualfname.substr(i+1, virtualfname.length() - i)); - } - - //**data dataset** - hid_t vdset = H5Dopen2( vfd, virtualDatasetname.c_str(), H5P_DEFAULT); - if (vdset < 0) { - H5Fclose(mfd); - return CloseFileOnError( vfd, std::string("Could not open virtual data dataset\n")); - } - sprintf(linkname, "/entry/data/%s",virtualDatasetname.c_str()); - if(H5Lcreate_external( relative_virtualfname.c_str(), virtualDatasetname.c_str(), - mfd, linkname, H5P_DEFAULT, H5P_DEFAULT) < 0) { - H5Fclose(mfd); mfd = 0; - return CloseFileOnError( vfd, std::string("Could not create link to data dataset\n")); - } - H5Dclose(vdset); - - //**paramter datasets** - for (unsigned int i = 0; i < parameterNames.size(); ++i){ - hid_t vdset_para = H5Dopen2( vfd, (std::string (parameterNames[i])).c_str(), H5P_DEFAULT); - if (vdset_para < 0) { + //open virtual file + vfd = H5Fopen( virtualfname.c_str(), H5F_ACC_RDWR, dfal); + if (vfd < 0) { H5Fclose(mfd); mfd = 0; - return CloseFileOnError( vfd, std::string("Could not open virtual parameter dataset to create link\n")); + throw RuntimeError("Could not open virtual file"); } - sprintf(linkname, "/entry/data/%s",(std::string (parameterNames[i])).c_str()); - if(H5Lcreate_external( relative_virtualfname.c_str(), (std::string (parameterNames[i])).c_str(), - mfd, linkname, H5P_DEFAULT, H5P_DEFAULT) < 0) { + // find relative path + std::string relative_virtualfname = virtualfname; + { + size_t i = virtualfname.rfind('/', virtualfname.length()); + if (i != std::string::npos) + relative_virtualfname = (virtualfname.substr(i+1, virtualfname.length() - i)); + } + + //**data dataset** + hid_t vdset = H5Dopen2( vfd, virtualDatasetname.c_str(), H5P_DEFAULT); + if (vdset < 0) { + H5Fclose(mfd); + throw RuntimeError("Could not open virtual data dataset"); + } + sprintf(linkname, "/entry/data/%s",virtualDatasetname.c_str()); + if(H5Lcreate_external( relative_virtualfname.c_str(), virtualDatasetname.c_str(), + mfd, linkname, H5P_DEFAULT, H5P_DEFAULT) < 0) { H5Fclose(mfd); mfd = 0; - return CloseFileOnError( vfd, std::string("Could not create link to virtual parameter dataset\n")); + throw RuntimeError("Could not create link to data dataset"); } - } + H5Dclose(vdset); - H5Fclose(mfd); mfd = 0; - H5Fclose(vfd); vfd = 0; - return 0; + //**paramter datasets** + for (unsigned int i = 0; i < parameterNames.size(); ++i){ + hid_t vdset_para = H5Dopen2( vfd, (std::string (parameterNames[i])).c_str(), H5P_DEFAULT); + if (vdset_para < 0) { + H5Fclose(mfd); mfd = 0; + throw RuntimeError("Could not open virtual parameter dataset to create link"); + } + sprintf(linkname, "/entry/data/%s",(std::string (parameterNames[i])).c_str()); + + if(H5Lcreate_external( relative_virtualfname.c_str(), (std::string (parameterNames[i])).c_str(), + mfd, linkname, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5Fclose(mfd); mfd = 0; + throw RuntimeError("Could not create link to virtual parameter dataset"); + } + } + + H5Fclose(mfd); mfd = 0; + H5Fclose(vfd); vfd = 0; + } catch () { + if(vfd > 0) + H5Fclose(vfd); + vfd = 0; + } } - /** - * Print Error msg and Close File and called on error - * @returns 1 for fail - */ - static int CloseFileOnError(hid_t& fd, const std::string msg) { - FILE_LOG(logERROR) << msg; - if(fd > 0) - H5Fclose(fd); - fd = 0; - return 1; - } - - /** * Get Data type in C * @param dtype datatype in C++ diff --git a/slsReceiverSoftware/include/Implementation.h b/slsReceiverSoftware/include/Implementation.h index 800344859..b2fc2863b 100755 --- a/slsReceiverSoftware/include/Implementation.h +++ b/slsReceiverSoftware/include/Implementation.h @@ -17,22 +17,16 @@ class slsDetectorDefs; class Implementation : private virtual slsDetectorDefs { public: - Implementation(); + Implementation(const detectorType d); virtual ~Implementation(); - /************************************************** * * * Configuration Parameters * * * * ************************************************/ - /** - * Set receiver type. It is the first function called by the client when - * connecting to receiver - * @param d detector type - * @return OK or FAIL - */ - int setDetectorType(const detectorType d); + + void setDetectorType(const detectorType d); int *getMultiDetectorSize() const; void setMultiDetectorSize(const int *size); int getDetectorPositionId() const; @@ -42,7 +36,7 @@ class Implementation : private virtual slsDetectorDefs { bool getSilentMode() const; void setSilentMode(const bool i); uint32_t getFifoDepth() const; - int setFifoDepth(const uint32_t i); + void setFifoDepth(const uint32_t i); frameDiscardPolicy getFrameDiscardPolicy() const; void setFrameDiscardPolicy(const frameDiscardPolicy i); bool getFramePaddingEnable() const; @@ -81,13 +75,13 @@ class Implementation : private virtual slsDetectorDefs { uint64_t getFramesCaught() const; uint64_t getAcquisitionIndex() const; std::vector getNumMissingPackets() const; - int startReceiver(std::string& err); + void startReceiver(); void setStoppedFlag(bool stopped); void stopReceiver(); void startReadout(); void shutDownUDPSockets(); void closeFiles(); - int restreamStop(); + void restreamStop(); /************************************************** @@ -97,7 +91,7 @@ class Implementation : private virtual slsDetectorDefs { * ************************************************/ int getNumberofUDPInterfaces() const; /* [Jungfrau] */ - int setNumberofUDPInterfaces(const int n); + void setNumberofUDPInterfaces(const int n); std::string getEthernetInterface() const; void setEthernetInterface(const std::string &c); std::string getEthernetInterface2() const; @@ -109,7 +103,7 @@ class Implementation : private virtual slsDetectorDefs { /* [Eiger][Jungfrau] */ void setUDPPortNumber2(const uint32_t i); int64_t getUDPSocketBufferSize() const; - int setUDPSocketBufferSize(const int64_t s); + void setUDPSocketBufferSize(const int64_t s); int64_t getActualUDPSocketBufferSize() const; @@ -119,10 +113,10 @@ class Implementation : private virtual slsDetectorDefs { * * * ************************************************/ bool getDataStreamEnable() const; - int setDataStreamEnable(const bool enable); + void setDataStreamEnable(const bool enable); uint32_t getStreamingFrequency() const; /* 0 for timer */ - int setStreamingFrequency(const uint32_t freq); + void setStreamingFrequency(const uint32_t freq); uint32_t getStreamingTimer() const; void setStreamingTimer(const uint32_t time_in_ms); uint32_t getStreamingPort() const; @@ -151,26 +145,26 @@ class Implementation : private virtual slsDetectorDefs { void setSubPeriod(const uint64_t i); uint32_t getNumberofAnalogSamples() const; /**[Ctb][Moench] */ - int setNumberofAnalogSamples(const uint32_t i); + void setNumberofAnalogSamples(const uint32_t i); uint32_t getNumberofDigitalSamples() const; /**[Ctb] */ - int setNumberofDigitalSamples(const uint32_t i); + void setNumberofDigitalSamples(const uint32_t i); uint32_t getDynamicRange() const; - int setDynamicRange(const uint32_t i); + void setDynamicRange(const uint32_t i); ROI getROI() const; /* [Gotthard] */ - int setROI(ROI arg); + void setROI(ROI arg); bool getTenGigaEnable() const; /* [Eiger][Ctb] */ - int setTenGigaEnable(const bool b); + void setTenGigaEnable(const bool b); int getFlippedDataX() const; void setFlippedDataX(int enable = -1); bool getGapPixelsEnable() const; /* [Eiger] */ - int setGapPixelsEnable(const bool b); + void setGapPixelsEnable(const bool b); bool getQuad() const; /* [Eiger] */ - int setQuad(const bool b); + void setQuad(const bool b); bool getActivate() const; /** [Eiger] If deactivated, receiver will create dummy data if deactivated padding is enabled (as it will receive nothing from detector) */ bool setActivate(const bool enable); @@ -182,13 +176,13 @@ class Implementation : private virtual slsDetectorDefs { void setReadNLines(const int value); readoutMode getReadoutMode() const; /* [Ctb] */ - int setReadoutMode(const readoutMode f); + void setReadoutMode(const readoutMode f); uint32_t getADCEnableMask() const; /* [Ctb][Moench] */ - int setADCEnableMask(const uint32_t mask); + void setADCEnableMask(const uint32_t mask); uint32_t getTenGigaADCEnableMask() const; /* [Ctb][Moench] */ - int setTenGigaADCEnableMask(const uint32_t mask); + void setTenGigaADCEnableMask(const uint32_t mask); std::vector getDbitList() const; /* [Ctb] */ void setDbitList(const std::vector v); @@ -215,11 +209,11 @@ class Implementation : private virtual slsDetectorDefs { void InitializeMembers(); void SetLocalNetworkParameters(); void SetThreadPriorities(); - int SetupFifoStructure(); + void SetupFifoStructure(); void ResetParametersforNewAcquisition(); - int CreateUDPSockets(); - int SetupWriter(); + void CreateUDPSockets(); + void SetupWriter(); void StartRunning(); diff --git a/slsReceiverSoftware/include/Listener.h b/slsReceiverSoftware/include/Listener.h index 67371fc1d..2b72b64ec 100755 --- a/slsReceiverSoftware/include/Listener.h +++ b/slsReceiverSoftware/include/Listener.h @@ -105,15 +105,13 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject { /** * Set thread priority * @priority priority - * @returns OK or FAIL */ - int SetThreadPriority(int priority); + void SetThreadPriority(int priority); /** * Creates UDP Sockets - * @return OK or FAIL */ - int CreateUDPSockets(); + void CreateUDPSockets(); /** * Shuts down and deletes UDP Sockets @@ -124,9 +122,8 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject { * Create & closes a dummy UDP socket * to set & get actual buffer size * @param s UDP socket buffer size to be set - * @return OK or FAIL of dummy socket creation */ - int CreateDummySocketForUDPSocketBufferSize(int64_t s); + void CreateDummySocketForUDPSocketBufferSize(int64_t s); /** * Set hard coded (calculated but not from detector) row and column diff --git a/slsReceiverSoftware/include/ThreadObject.h b/slsReceiverSoftware/include/ThreadObject.h index 932dc2630..6d68a8db4 100755 --- a/slsReceiverSoftware/include/ThreadObject.h +++ b/slsReceiverSoftware/include/ThreadObject.h @@ -66,9 +66,8 @@ class ThreadObject : private virtual slsDetectorDefs { /** * Create Thread, sets semaphore, alive and killThread - * @return OK if successful, else FAIL */ - int CreateThread(); + void CreateThread(); private: diff --git a/slsReceiverSoftware/src/BinaryFile.cpp b/slsReceiverSoftware/src/BinaryFile.cpp index eb3f36341..bad78e8f2 100755 --- a/slsReceiverSoftware/src/BinaryFile.cpp +++ b/slsReceiverSoftware/src/BinaryFile.cpp @@ -42,20 +42,18 @@ slsDetectorDefs::fileFormat BinaryFile::GetFileType() { } -int BinaryFile::CreateFile() { +void BinaryFile::CreateFile() { numFramesInFile = 0; numActualPacketsInFile = 0; currentFileName = BinaryFileStatic::CreateFileName(*filePath, *fileNamePrefix, *fileIndex, subFileIndex, *detIndex, *numUnitsPerDetector, index); - if (BinaryFileStatic::CreateDataFile(filefd, *overWriteEnable, currentFileName, FILE_BUFFER_SIZE) == FAIL) - return FAIL; + BinaryFileStatic::CreateDataFile(filefd, *overWriteEnable, currentFileName, FILE_BUFFER_SIZE); if(!(*silentMode)) { FILE_LOG(logINFO) << "[" << *udpPortNumber << "]: Binary File created: " << currentFileName; } - return OK; } void BinaryFile::CloseCurrentFile() { @@ -68,7 +66,7 @@ void BinaryFile::CloseAllFiles() { BinaryFileStatic::CloseDataFile(masterfd); } -int BinaryFile::WriteToFile(char* buffer, int buffersize, uint64_t fnum, uint32_t nump) { +void BinaryFile::WriteToFile(char* buffer, int buffersize, uint64_t fnum, uint32_t nump) { // check if maxframesperfile = 0 for infinite if ((*maxFramesPerFile) && (numFramesInFile >= (*maxFramesPerFile))) { CloseCurrentFile(); @@ -107,14 +105,12 @@ int BinaryFile::WriteToFile(char* buffer, int buffersize, uint64_t fnum, uint32_ // if write error if (ret != buffersize) { - FILE_LOG(logERROR) << index << " Error: Write to file failed for image number " << fnum; - return FAIL; + throw sls::RuntimeError(std::to_string(index) + " : Write to file failed for image number " + std::to_string(fnum)); } - return OK; } -int BinaryFile::CreateMasterFile(bool mfwenable, masterAttributes& attr) { +void BinaryFile::CreateMasterFile(bool mfwenable, masterAttributes& attr) { //beginning of every acquisition numFramesInFile = 0; numActualPacketsInFile = 0; @@ -126,10 +122,9 @@ int BinaryFile::CreateMasterFile(bool mfwenable, masterAttributes& attr) { FILE_LOG(logINFO) << "Master File: " << masterFileName; } attr.version = BINARY_WRITER_VERSION; - return BinaryFileStatic::CreateMasterDataFile(masterfd, masterFileName, + BinaryFileStatic::CreateMasterDataFile(masterfd, masterFileName, *overWriteEnable, attr); } - return OK; } diff --git a/slsReceiverSoftware/src/ClientInterface.cpp b/slsReceiverSoftware/src/ClientInterface.cpp index 91f5f2a9a..1d82296b4 100755 --- a/slsReceiverSoftware/src/ClientInterface.cpp +++ b/slsReceiverSoftware/src/ClientInterface.cpp @@ -268,7 +268,7 @@ void ClientInterface::VerifyLock() { void ClientInterface::VerifyIdle(Interface &socket) { if (impl()->getStatus() != IDLE) { std::ostringstream oss; - oss << "Can not execute " << getFunctionNameFromEnum((enum detFuncs)fnum) + oss << "Can not execute " << GetFunctionNameFromEnum((enum detFuncs)fnum) << " when receiver is not idle"; throw sls::SocketError(oss.str()); } @@ -286,7 +286,7 @@ int ClientInterface::exec_command(Interface &socket) { if (!pipe) { throw RuntimeError("Executing Command failed\n"); } else { - while (!feof(pipe.get())) { + while (!feof(pipe.Get())) { if (fgets(temp.data(), tempsize, pipe.get()) != nullptr) sresult += temp.data(); } @@ -473,11 +473,11 @@ int ClientInterface::set_detector_type(Interface &socket) { break; } - if (receiver == nullptr) { - receiver = sls::make_unique(); - } - myDetectorType = arg; - if (impl()->setDetectorType(myDetectorType) == FAIL) { + try { + myDetectorType = GENERIC; + receiver = sls::make_unique(arg); + myDetectorType = arg; + } catch (...) { throw RuntimeError("Could not set detector type"); } @@ -525,8 +525,11 @@ int ClientInterface::set_roi(Interface &socket) { functionNotImplemented(); VerifyIdle(socket); - if (impl()->setROI(arg) == FAIL) + try { + impl()->setROI(arg); + } catch(const RuntimeError &e) { throw RuntimeError("Could not set ROI"); + } return socket.Send(OK); } @@ -543,7 +546,11 @@ int ClientInterface::set_num_analog_samples(Interface &socket) { if (myDetectorType != CHIPTESTBOARD && myDetectorType != MOENCH) { functionNotImplemented(); } - ret = impl()->setNumberofAnalogSamples(value); + try { + impl()->setNumberofAnalogSamples(value); + } catch(const RuntimeError &e) { + throw RuntimeError("Could not set num analog samples to " + std::to_string(value) + " due to fifo structure memory allocation."); + } return socket.Send(OK); } @@ -554,7 +561,11 @@ int ClientInterface::set_num_digital_samples(Interface &socket) { if (myDetectorType != CHIPTESTBOARD && myDetectorType != MOENCH) { functionNotImplemented(); } - ret = impl()->setNumberofDigitalSamples(value); + try { + impl()->setNumberofDigitalSamples(value); + } catch(const RuntimeError &e) { + throw RuntimeError("Could not set num digital samples to " + std::to_string(value) + " due to fifo structure memory allocation."); + } return socket.Send(OK); } @@ -613,8 +624,9 @@ int ClientInterface::set_dynamic_range(Interface &socket) { if (!exists) { modeNotImplemented("Dynamic range", dr); } else { - ret = impl()->setDynamicRange(dr); - if (ret == FAIL) { + try { + impl()->setDynamicRange(dr); + } catch(const RuntimeError &e) { throw RuntimeError("Could not allocate memory for fifo or " "could not start listening/writing threads"); } @@ -631,10 +643,7 @@ int ClientInterface::set_streaming_frequency(Interface &socket) { if (index >= 0) { VerifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting streaming frequency: " << index; - ret = impl()->setStreamingFrequency(index); - if (ret == FAIL) { - throw RuntimeError("Could not allocate memory for listening fifo"); - } + impl()->setStreamingFrequency(index); } int retval = impl()->getStreamingFrequency(); validate(index, retval, "set streaming frequency", DEC); @@ -650,11 +659,7 @@ int ClientInterface::get_status(Interface &socket) { int ClientInterface::start_receiver(Interface &socket) { if (impl()->getStatus() == IDLE) { FILE_LOG(logDEBUG1) << "Starting Receiver"; - std::string err; - ret = impl()->startReceiver(err); - if (ret == FAIL) { - throw RuntimeError(err); - } + impl()->startReceiver(); } return socket.Send(OK); } @@ -797,7 +802,11 @@ int ClientInterface::enable_tengiga(Interface &socket) { if (val >= 0) { VerifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting 10GbE:" << val; - ret = impl()->setTenGigaEnable(val); + try { + impl()->setTenGigaEnable(val); + } catch(const RuntimeError &e) { + throw RuntimeError("Could not set 10GbE."); + } } int retval = impl()->getTenGigaEnable(); validate(val, retval, "set 10GbE", DEC); @@ -810,7 +819,11 @@ int ClientInterface::set_fifo_depth(Interface &socket) { if (value >= 0) { VerifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting fifo depth:" << value; - impl()->setFifoDepth(value); + try { + impl()->setFifoDepth(value); + } catch(const RuntimeError &e) { + throw RuntimeError("Could not set fifo depth due to fifo structure memory allocation."); + } } int retval = impl()->getFifoDepth(); validate(value, retval, std::string("set fifo depth"), DEC); @@ -839,7 +852,11 @@ int ClientInterface::set_data_stream_enable(Interface &socket) { if (index >= 0) { VerifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting data stream enable:" << index; - impl()->setDataStreamEnable(index); + try { + impl()->setDataStreamEnable(index); + } catch(const RuntimeError &e) { + throw RuntimeError("Could not set data stream enable to " + std::to_string(index)); + } } auto retval = static_cast(impl()->getDataStreamEnable()); validate(index, retval, "set data stream enable", DEC); @@ -969,7 +986,11 @@ int ClientInterface::enable_gap_pixels(Interface &socket) { if (enable >= 0) { VerifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting gap pixels enable:" << enable; - impl()->setGapPixelsEnable(static_cast(enable)); + try { + impl()->setGapPixelsEnable(static_cast(enable)); + } catch(const RuntimeError &e) { + throw RuntimeError("Could not set gap pixels enable to " + std::to_string(enable)); + } } auto retval = static_cast(impl()->getGapPixelsEnable()); validate(enable, retval, "set gap pixels enable", DEC); @@ -1013,10 +1034,7 @@ int ClientInterface::set_udp_socket_buffer_size(Interface &socket) { if (index >= 0) { VerifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting UDP Socket Buffer size: " << index; - if (impl()->setUDPSocketBufferSize(index) == FAIL) { - throw RuntimeError( - "Could not create dummy UDP Socket to test buffer size"); - } + impl()->setUDPSocketBufferSize(index); } int64_t retval = impl()->getUDPSocketBufferSize(); if (index != 0) @@ -1127,7 +1145,11 @@ int ClientInterface::set_readout_mode(Interface &socket) { if (arg >= 0) { VerifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting readout mode: " << arg; - impl()->setReadoutMode(arg); + try { + impl()->setReadoutMode(arg); + } catch(const RuntimeError &e) { + throw RuntimeError("Could not set read out mode due to fifo memory allocation."); + } } auto retval = impl()->getReadoutMode(); validate(static_cast(arg), static_cast(retval), @@ -1140,7 +1162,11 @@ int ClientInterface::set_adc_mask(Interface &socket) { auto arg = socket.Receive(); VerifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting 1Gb ADC enable mask: " << arg; - impl()->setADCEnableMask(arg); + try { + impl()->setADCEnableMask(arg); + } catch(const RuntimeError &e) { + throw RuntimeError("Could not set adc enable mask due to fifo memory allcoation"); + } auto retval = impl()->getADCEnableMask(); if (retval != arg) { std::ostringstream os; @@ -1190,10 +1216,11 @@ int ClientInterface::set_quad_type(Interface &socket) { if (quadEnable >= 0) { VerifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting quad:" << quadEnable; - ret = impl()->setQuad(quadEnable == 0 ? false : true); - if (ret == FAIL) { - throw RuntimeError("Could not set Quad due to fifo structure"); - } + try { + impl()->setQuad(quadEnable == 0 ? false : true); + } catch(const RuntimeError &e) { + throw RuntimeError("Could not set quad to " + std::to_string(quadEnable) + " due to fifo strucutre memory allocation"); + } } int retval = impl()->getQuad() ? 1 : 0; validate(quadEnable, retval, "set quad", DEC); @@ -1296,8 +1323,10 @@ int ClientInterface::set_num_interfaces(Interface &socket) { throw RuntimeError("Number of interfaces not implemented for this detector"); } FILE_LOG(logDEBUG1) << "Setting Number of UDP Interfaces:" << arg; - if (impl()->setNumberofUDPInterfaces(arg) == FAIL) { - throw RuntimeError("Failed to set number of interfaces"); + try { + impl()->setNumberofUDPInterfaces(arg); + } catch(const RuntimeError &e) { + throw RuntimeError("Failed to set number of interfaces to " + std::to_string(arg)); } return socket.Send(OK); } @@ -1306,7 +1335,11 @@ int ClientInterface::set_adc_mask_10g(Interface &socket) { auto arg = socket.Receive(); VerifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting 10Gb ADC enable mask: " << arg; - impl()->setTenGigaADCEnableMask(arg); + try { + impl()->setTenGigaADCEnableMask(arg); + } catch(const RuntimeError &e) { + throw RuntimeError("Could not set 10Gb adc enable mask due to fifo memory allcoation"); + } auto retval = impl()->getTenGigaADCEnableMask(); if (retval != arg) { std::ostringstream os; diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index 15320bf6c..7d74bb647 100755 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -62,11 +62,8 @@ DataProcessor::DataProcessor(int ind, detectorType dtype, Fifo* f, rawDataModifyReadyCallBack(nullptr), pRawDataReady(nullptr) { - if(ThreadObject::CreateThread() == FAIL) - throw sls::RuntimeError("Could not create processing thread"); - + ThreadObject::CreateThread(); FILE_LOG(logDEBUG) << "DataProcessor " << ind << " created"; - memset((void*)&timerBegin, 0, sizeof(timespec)); } @@ -158,13 +155,14 @@ void DataProcessor::SetGeneralData(GeneralData* g) { } -int DataProcessor::SetThreadPriority(int priority) { +void DataProcessor::SetThreadPriority(int priority) { struct sched_param param; param.sched_priority = priority; - if (pthread_setschedparam(thread, SCHED_FIFO, ¶m) == EPERM) - return FAIL; + if (pthread_setschedparam(thread, SCHED_FIFO, ¶m) == EPERM) { + throw sls::RuntimeError("Could not prioritize dataprocessing threads. " + "(No Root Privileges?)"); + } FILE_LOG(logINFO) << "Processor Thread Priority set to " << priority; - return OK; } @@ -220,16 +218,14 @@ void DataProcessor::SetupFileWriter(bool fwe, int* nd, uint32_t* maxf, } // only the first file -int DataProcessor::CreateNewFile(masterAttributes& attr) { - if (file == nullptr) - return FAIL; +void DataProcessor::CreateNewFile(masterAttributes& attr) { + if (file == nullptr) { + throw sls::RuntimeError("file object not contstructed"); + } file->CloseAllFiles(); file->resetSubFileIndex(); - if (file->CreateMasterFile(*masterFileWriteEnable, attr) == FAIL) - return FAIL; - if (file->CreateFile() == FAIL) - return FAIL; - return OK; + file->CreateMasterFile(*masterFileWriteEnable, attr); + file->CreateFile(); } @@ -240,7 +236,11 @@ void DataProcessor::CloseFiles() { void DataProcessor::EndofAcquisition(bool anyPacketsCaught, uint64_t numf) { if ((file != nullptr) && file->GetFileType() == HDF5) { - file->EndofAcquisition(anyPacketsCaught, numf); + try { + file->EndofAcquisition(anyPacketsCaught, numf); + } catch (const sls::RuntimeError &e) { + ;// ignore for now //TODO: send error to client via stop receiver + } } } @@ -352,10 +352,15 @@ void DataProcessor::ProcessAnImage(char* buf) { // write to file - if (file != nullptr) - file->WriteToFile(buf + FIFO_HEADER_NUMBYTES, - sizeof(sls_receiver_header) + (uint32_t)(*((uint32_t*)buf)), //+ size of data (resizable from previous call back - fnum-firstIndex, nump); + if (file != nullptr) { + try { + file->WriteToFile(buf + FIFO_HEADER_NUMBYTES, + sizeof(sls_receiver_header) + (uint32_t)(*((uint32_t*)buf)), //+ size of data (resizable from previous call back + fnum-firstIndex, nump); + } catch(const sls::RuntimeError &e) { + ; //ignore write exception for now (TODO: send error message via stopReceiver tcp) + } + } } diff --git a/slsReceiverSoftware/src/DataStreamer.cpp b/slsReceiverSoftware/src/DataStreamer.cpp index 039c7f720..f79c4010a 100755 --- a/slsReceiverSoftware/src/DataStreamer.cpp +++ b/slsReceiverSoftware/src/DataStreamer.cpp @@ -38,12 +38,8 @@ DataStreamer::DataStreamer(int ind, Fifo* f, uint32_t* dr, ROI* r, numDet[0] = nd[0]; numDet[1] = nd[1]; - if(ThreadObject::CreateThread() == FAIL) - throw sls::RuntimeError("Could not create streaming thread"); - + ThreadObject::CreateThread(); FILE_LOG(logDEBUG) << "DataStreamer " << ind << " created"; - - // memset(fileNametoStream, 0, MAX_STR_LENGTH); } @@ -82,7 +78,6 @@ void DataStreamer::ResetParametersforNewAcquisition(const std::string& fname){ startedFlag = false; firstIndex = 0; - // strcpy(fileNametoStream, fname); fileNametoStream = fname; if (completeBuffer) { delete[] completeBuffer; @@ -109,13 +104,14 @@ void DataStreamer::SetGeneralData(GeneralData* g) { generalData->Print(); } -int DataStreamer::SetThreadPriority(int priority) { +void DataStreamer::SetThreadPriority(int priority) { struct sched_param param; param.sched_priority = priority; - if (pthread_setschedparam(thread, SCHED_FIFO, ¶m) == EPERM) - return FAIL; + if (pthread_setschedparam(thread, SCHED_FIFO, ¶m) == EPERM) { + throw sls::RuntimeError("Could not prioritize datastreaming threads. " + "(No Root Privileges?)"); + } FILE_LOG(logINFO) << "Streamer Thread Priority set to " << priority; - return OK; } void DataStreamer::SetNumberofDetectors(int* nd) { @@ -258,14 +254,12 @@ int DataStreamer::SendHeader(sls_receiver_header* rheader, uint32_t size, uint32 -int DataStreamer::RestreamStop() { +void DataStreamer::RestreamStop() { //send dummy header int ret = zmqSocket->SendHeaderData(index, true, SLS_DETECTOR_JSON_HEADER_VERSION); if (!ret) { - FILE_LOG(logERROR) << "Could not Restream Dummy Header via ZMQ for port " << zmqSocket->GetPortNumber(); - return FAIL; + throw sls::RuntimeError("Could not restream Dummy Header via ZMQ for port " + std::to_string(zmqSocket->GetPortNumber())); } - return OK; } diff --git a/slsReceiverSoftware/src/Fifo.cpp b/slsReceiverSoftware/src/Fifo.cpp index 9e744a0d7..0271f8685 100755 --- a/slsReceiverSoftware/src/Fifo.cpp +++ b/slsReceiverSoftware/src/Fifo.cpp @@ -23,8 +23,7 @@ Fifo::Fifo(int ind, uint32_t fifoItemSize, uint32_t depth): status_fifoBound(0), status_fifoFree(depth){ FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; - if(CreateFifos(fifoItemSize) == FAIL) - throw sls::RuntimeError("Could not create FIFO"); + CreateFifos(fifoItemSize); } @@ -35,7 +34,7 @@ Fifo::~Fifo() { -int Fifo::CreateFifos(uint32_t fifoItemSize) { +void Fifo::CreateFifos(uint32_t fifoItemSize) { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; //destroy if not already @@ -49,8 +48,7 @@ int Fifo::CreateFifos(uint32_t fifoItemSize) { size_t mem_len = fifoItemSize * fifoDepth * sizeof(char); memory = (char*) malloc (mem_len); if (memory == nullptr){ - FILE_LOG(logERROR) << "Could not allocate memory for fifos"; - return FAIL; + throw sls::RuntimeError("Could not allocate memory for fifos"); } memset(memory, 0, mem_len); FILE_LOG(logDEBUG) << "Memory Allocated " << index << ": " << mem_len << " bytes"; @@ -64,7 +62,6 @@ int Fifo::CreateFifos(uint32_t fifoItemSize) { } } FILE_LOG(logINFO) << "Fifo " << index << " reconstructed Depth (rx_fifodepth): " << fifoFree->getDataValue(); - return OK; } diff --git a/slsReceiverSoftware/src/HDF5File.cpp b/slsReceiverSoftware/src/HDF5File.cpp index 512dc6b32..2fd45038b 100755 --- a/slsReceiverSoftware/src/HDF5File.cpp +++ b/slsReceiverSoftware/src/HDF5File.cpp @@ -128,7 +128,7 @@ void HDF5File::UpdateDataType() { } -int HDF5File::CreateFile() { +void HDF5File::CreateFile() { numFilesinAcquisition++; numFramesInFile = 0; numActualPacketsInFile = 0; @@ -143,21 +143,22 @@ int HDF5File::CreateFile() { (((extNumImages - subFileIndex) > (*maxFramesPerFile)) ? // save up to maximum at a time (*maxFramesPerFile) : (extNumImages-subFileIndex))); pthread_mutex_lock(&Mutex); - if (HDF5FileStatic::CreateDataFile(index, *overWriteEnable, currentFileName, (*numImages > 1), + try{ + HDF5FileStatic::CreateDataFile(index, *overWriteEnable, currentFileName, (*numImages > 1), subFileIndex, framestosave, nPixelsY, ((*dynamicRange==4) ? (nPixelsX/2) : nPixelsX), datatype, filefd, dataspace, dataset, HDF5_WRITER_VERSION, MAX_CHUNKED_IMAGES, dataspace_para, dataset_para, - parameterNames, parameterDataTypes) == FAIL) { + parameterNames, parameterDataTypes); + } catch(const RuntimeError &e) { pthread_mutex_unlock(&Mutex); - return FAIL; + throw; } pthread_mutex_unlock(&Mutex); if(!(*silentMode)) { FILE_LOG(logINFO) << *udpPortNumber << ": HDF5 File created: " << currentFileName; } - return OK; } @@ -195,7 +196,7 @@ void HDF5File::CloseAllFiles() { } -int HDF5File::WriteToFile(char* buffer, int buffersize, uint64_t fnum, uint32_t nump) { +void HDF5File::WriteToFile(char* buffer, int buffersize, uint64_t fnum, uint32_t nump) { // check if maxframesperfile = 0 for infinite if ((*maxFramesPerFile) && (numFramesInFile >= (*maxFramesPerFile))) { @@ -207,40 +208,38 @@ int HDF5File::WriteToFile(char* buffer, int buffersize, uint64_t fnum, uint32_t numActualPacketsInFile += nump; pthread_mutex_lock(&Mutex); + try { // extend dataset (when receiver start followed by many status starts (jungfrau))) if (fnum >= extNumImages) { - if (HDF5FileStatic::ExtendDataset(index, dataspace, dataset, - dataspace_para, dataset_para, *numImages) == OK) { - if (!(*silentMode)) { - FILE_LOG(logINFO) << index << " Extending HDF5 dataset by " << - extNumImages << ", Total x Dimension: " << (extNumImages + *numImages); - } - extNumImages += *numImages; + HDF5FileStatic::ExtendDataset(index, dataspace, dataset, + dataspace_para, dataset_para, *numImages); + if (!(*silentMode)) { + FILE_LOG(logINFO) << index << " Extending HDF5 dataset by " << + extNumImages << ", Total x Dimension: " << (extNumImages + *numImages); } + extNumImages += *numImages; } - if (HDF5FileStatic::WriteDataFile(index, buffer + sizeof(sls_receiver_header), + HDF5FileStatic::WriteDataFile(index, buffer + sizeof(sls_receiver_header), // infinite then no need for %maxframesperfile ((*maxFramesPerFile == 0) ? fnum : fnum%(*maxFramesPerFile)), nPixelsY, ((*dynamicRange==4) ? (nPixelsX/2) : nPixelsX), - dataspace, dataset, datatype) == OK) { + dataspace, dataset, datatype); - if (HDF5FileStatic::WriteParameterDatasets(index, dataspace_para, + HDF5FileStatic::WriteParameterDatasets(index, dataspace_para, // infinite then no need for %maxframesperfile ((*maxFramesPerFile == 0) ? fnum : fnum%(*maxFramesPerFile)), dataset_para, (sls_receiver_header*) (buffer), - parameterDataTypes) == OK) { - pthread_mutex_unlock(&Mutex); - return OK; - } + parameterDataTypes); + } catch (const RuntimeError &e) { + pthread_mutex_unlock(&Mutex); + throw; } pthread_mutex_unlock(&Mutex); - FILE_LOG(logERROR) << index << "Write to file failed"; - return FAIL; } -int HDF5File::CreateMasterFile(bool mfwenable, masterAttributes& attr) { +void HDF5File::CreateMasterFile(bool mfwenable, masterAttributes& attr) { //beginning of every acquisition numFramesInFile = 0; @@ -256,12 +255,14 @@ int HDF5File::CreateMasterFile(bool mfwenable, masterAttributes& attr) { } pthread_mutex_lock(&Mutex); attr.version = HDF5_WRITER_VERSION; - int ret = HDF5FileStatic::CreateMasterDataFile(masterfd, masterFileName, + try{ + HDF5FileStatic::CreateMasterDataFile(masterfd, masterFileName, *overWriteEnable, attr); - pthread_mutex_unlock(&Mutex); - return ret; + } catch (const RuntimeError &e) { + pthread_mutex_unlock(&Mutex); + throw; + } } - return OK; } @@ -286,15 +287,15 @@ void HDF5File::EndofAcquisition(bool anyPacketsCaught, uint64_t numf) { // called only by the one maser receiver -int HDF5File::CreateVirtualFile(uint64_t numf) { +void HDF5File::CreateVirtualFile(uint64_t numf) { pthread_mutex_lock(&Mutex); std::string vname = HDF5FileStatic::CreateVirtualFileName(*filePath, *fileNamePrefix, *fileIndex); if(!(*silentMode)) { FILE_LOG(logINFO) << "Virtual File: " << vname; } - - int ret = HDF5FileStatic::CreateVirtualDataFile(vname, + try { + HDF5FileStatic::CreateVirtualDataFile(vname, virtualfd, masterFileName, *filePath, *fileNamePrefix, *fileIndex, (*numImages > 1), *detIndex, *numUnitsPerDetector, @@ -305,12 +306,15 @@ int HDF5File::CreateVirtualFile(uint64_t numf) { numDetY, numDetX, nPixelsY, ((*dynamicRange==4) ? (nPixelsX/2) : nPixelsX), HDF5_WRITER_VERSION, parameterNames, parameterDataTypes); - pthread_mutex_unlock(&Mutex); - return ret; + } catch (const RuntimeError &e) { + pthread_mutex_unlock(&Mutex); + throw; + } + pthread_mutex_unlock(&Mutex); } // called only by the one maser receiver -int HDF5File::LinkVirtualFileinMasterFile() { +void HDF5File::LinkVirtualFileinMasterFile() { //dataset name std::ostringstream osfn; osfn << "/data"; @@ -318,8 +322,12 @@ int HDF5File::LinkVirtualFileinMasterFile() { std::string dsetname = osfn.str(); pthread_mutex_lock(&Mutex); - int ret = HDF5FileStatic::LinkVirtualInMaster(masterFileName, currentFileName, + try { + HDF5FileStatic::LinkVirtualInMaster(masterFileName, currentFileName, dsetname, parameterNames); + } catch (const RuntimeError &e) { + pthread_mutex_unlock(&Mutex); + throw; + } pthread_mutex_unlock(&Mutex); - return ret; } diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index 4503eee2b..4cfc103ad 100755 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -18,9 +18,10 @@ /** cosntructor & destructor */ -Implementation::Implementation() { +Implementation::Implementation(const detectorType d) { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; InitializeMembers(); + setDetectorType(d); } Implementation::~Implementation() { @@ -162,11 +163,7 @@ void Implementation::SetThreadPriorities() { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; for (const auto &it : listener) { - if (it->SetThreadPriority(LISTENER_PRIORITY) == FAIL) { - FILE_LOG(logWARNING) << "Could not prioritize listener threads. " - "(No Root Privileges?)"; - return; - } + it->SetThreadPriority(LISTENER_PRIORITY); } std::ostringstream osfn; osfn << "Priorities set - " @@ -176,7 +173,7 @@ void Implementation::SetThreadPriorities() { FILE_LOG(logINFO) << osfn.str(); } -int Implementation::SetupFifoStructure() { +void Implementation::SetupFifoStructure() { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; fifo.clear(); @@ -189,11 +186,8 @@ int Implementation::SetupFifoStructure() { (generalData->imageSize) + (generalData->fifoBufferHeaderSize), fifoDepth)); } catch (...) { - FILE_LOG(logERROR) - << "Could not allocate memory for fifo structure of index " - << i; fifo.clear(); - return FAIL; + throw sls::RuntimeError("Could not allocate memory for fifo structure " + std::to_string(i)); } // set the listener & dataprocessor threads to point to the right fifo if (listener.size()) @@ -210,7 +204,6 @@ int Implementation::SetupFifoStructure() { fifoDepth) << " bytes"; FILE_LOG(logINFO) << numThreads << " Fifo structure(s) reconstructed"; - return OK; } @@ -221,10 +214,8 @@ int Implementation::SetupFifoStructure() { * * * ************************************************/ -int Implementation::setDetectorType(const detectorType d) { +void Implementation::setDetectorType(const detectorType d) { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; - DeleteMembers(); - InitializeMembers(); myDetectorType = d; switch (myDetectorType) { case GOTTHARD: @@ -237,8 +228,7 @@ int Implementation::setDetectorType(const detectorType d) { << " Receiver *****"; break; default: - FILE_LOG(logERROR) << "This is an unknown receiver type " << (int)d; - return FAIL; + throw sls::RuntimeError("This is an unknown receiver type " + std::to_string(static_cast(d))); } // set detector specific variables @@ -270,10 +260,7 @@ int Implementation::setDetectorType(const detectorType d) { framesPerFile = generalData->maxFramesPerFile; SetLocalNetworkParameters(); - if (SetupFifoStructure() == FAIL) { - FILE_LOG(logERROR) << "Could not allocate memory for fifo structure"; - return FAIL; - } + SetupFifoStructure(); // create threads for (int i = 0; i < numThreads; ++i) { @@ -293,12 +280,9 @@ int Implementation::setDetectorType(const detectorType d) { &silentMode, &quadEnable, &ctbDbitList, &ctbDbitOffset, &ctbAnalogDataBytes)); } catch (...) { - FILE_LOG(logERROR) - << "Could not create listener/dataprocessor threads (index:" - << i << ")"; listener.clear(); dataProcessor.clear(); - return FAIL; + throw sls::RuntimeError("Could not create listener/dataprocessor threads (index:" + std::to_string(i) + ")"); } } @@ -311,7 +295,6 @@ int Implementation::setDetectorType(const detectorType d) { SetThreadPriorities(); FILE_LOG(logDEBUG) << " Detector type set to " << sls::ToString(d); - return OK; } int *Implementation::getMultiDetectorSize() const { @@ -404,14 +387,12 @@ uint32_t Implementation::getFifoDepth() const { return fifoDepth; } -int Implementation::setFifoDepth(const uint32_t i) { +void Implementation::setFifoDepth(const uint32_t i) { if (fifoDepth != i) { fifoDepth = i; - if (SetupFifoStructure() == FAIL) - throw sls::RuntimeError("Failed to setup fifo structure"); + SetupFifoStructure(); } FILE_LOG(logINFO) << "Fifo Depth: " << i; - return OK; } slsDetectorDefs::frameDiscardPolicy @@ -625,18 +606,14 @@ std::vector Implementation::getNumMissingPackets() const { return mp; } -int Implementation::startReceiver(std::string& err) { +void Implementation::startReceiver() { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; FILE_LOG(logINFO) << "Starting Receiver"; stoppedFlag = false; ResetParametersforNewAcquisition(); // listener - if (CreateUDPSockets() == FAIL) { - err.assign("Could not create UDP Socket(s)."); - FILE_LOG(logERROR) << err; - return FAIL; - } + CreateUDPSockets(); // callbacks if (startAcquisitionCallBack) { @@ -651,11 +628,7 @@ int Implementation::startReceiver(std::string& err) { // processor->writer if (fileWriteEnable) { - if (SetupWriter() == FAIL) { - err.assign("Could not create file.\n"); - FILE_LOG(logERROR) << err; - return FAIL; - } + SetupWriter(); } else FILE_LOG(logINFO) << "File Write Disabled"; @@ -669,7 +642,6 @@ int Implementation::startReceiver(std::string& err) { FILE_LOG(logINFO) << "Receiver Started"; FILE_LOG(logINFO) << "Status: " << sls::ToString(status); - return OK; } void Implementation::setStoppedFlag(bool stopped) { @@ -817,14 +789,12 @@ void Implementation::closeFiles() { dataProcessor[0]->EndofAcquisition(anycaught, maxIndexCaught); } -int Implementation::restreamStop() { +void Implementation::restreamStop() { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; for (const auto &it : dataStreamer) { - if (it->RestreamStop() == FAIL) - throw sls::RuntimeError("Could not restream stop packet"); + it->RestreamStop(); } FILE_LOG(logINFO) << "Restreaming Dummy Header via ZMQ successful"; - return OK; } void Implementation::ResetParametersforNewAcquisition() { @@ -844,29 +814,23 @@ void Implementation::ResetParametersforNewAcquisition() { } } -int Implementation::CreateUDPSockets() { +void Implementation::CreateUDPSockets() { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; - bool error = false; - for (unsigned int i = 0; i < listener.size(); ++i) { - if (listener[i]->CreateUDPSockets() == FAIL) { - error = true; - break; + try{ + for (unsigned int i = 0; i < listener.size(); ++i) { + listener[i]->CreateUDPSockets(); } - } - - if (error) { + } catch(const sls::RuntimeError &e) { shutDownUDPSockets(); - return FAIL; + throw sls::RuntimeError("Could not create UDP Socket(s)."); } FILE_LOG(logDEBUG) << "UDP socket(s) created successfully."; - return OK; } -int Implementation::SetupWriter() { +void Implementation::SetupWriter() { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; - bool error = false; masterAttributes attr; attr.detectorType = myDetectorType; attr.dynamicRange = dynamicRange; @@ -892,18 +856,16 @@ int Implementation::SetupWriter() { for (auto &i : ctbDbitList) { attr.dbitlist |= (1 << i); } - for (unsigned int i = 0; i < dataProcessor.size(); ++i) - if (dataProcessor[i]->CreateNewFile(attr) == FAIL) { - error = true; - break; + + try { + for (unsigned int i = 0; i < dataProcessor.size(); ++i) { + dataProcessor[i]->CreateNewFile(attr); } - if (error) { + } catch(const sls::RuntimeError &e) { shutDownUDPSockets(); closeFiles(); - return FAIL; + throw sls::RuntimeError("Could not create file."); } - - return OK; } void Implementation::StartRunning() { @@ -935,7 +897,7 @@ int Implementation::getNumberofUDPInterfaces() const { return numUDPInterfaces; } -int Implementation::setNumberofUDPInterfaces(const int n) { +void Implementation::setNumberofUDPInterfaces(const int n) { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; if (numUDPInterfaces != n) { @@ -959,8 +921,7 @@ int Implementation::setNumberofUDPInterfaces(const int n) { udpSocketBufferSize = generalData->defaultUdpSocketBufferSize; // fifo - if (SetupFifoStructure() == FAIL) - return FAIL; + SetupFifoStructure(); // create threads for (int i = 0; i < numThreads; ++i) { @@ -984,12 +945,9 @@ int Implementation::setNumberofUDPInterfaces(const int n) { &ctbDbitOffset, &ctbAnalogDataBytes)); dataProcessor[i]->SetGeneralData(generalData); } catch (...) { - FILE_LOG(logERROR) - << "Could not create listener/dataprocessor threads (index:" - << i << ")"; listener.clear(); dataProcessor.clear(); - return FAIL; + throw sls::RuntimeError("Could not create listener/dataprocessor threads (index:" + std::to_string(i) + ")"); } // streamer threads if (dataStreamEnable) { @@ -1009,14 +967,11 @@ int Implementation::setNumberofUDPInterfaces(const int n) { &numThreads, streamingPort, streamingSrcIP); } catch (...) { - FILE_LOG(logERROR) - << "Could not create datastreamer threads (index:" << i - << ")"; if (dataStreamEnable) { dataStreamer.clear(); dataStreamEnable = false; } - return FAIL; + throw sls::RuntimeError("Could not create datastreamer threads (index:" + std::to_string(i) + ")"); } } } @@ -1041,13 +996,10 @@ int Implementation::setNumberofUDPInterfaces(const int n) { } // test socket buffer size with current set up - if (setUDPSocketBufferSize(0) == FAIL) { - return FAIL; - } + setUDPSocketBufferSize(0); } FILE_LOG(logINFO) << "Number of Interfaces: " << numUDPInterfaces; - return OK; } std::string Implementation::getEthernetInterface() const { @@ -1103,22 +1055,17 @@ int64_t Implementation::getUDPSocketBufferSize() const { return udpSocketBufferSize; } -int Implementation::setUDPSocketBufferSize(const int64_t s) { +void Implementation::setUDPSocketBufferSize(const int64_t s) { int64_t size = (s == 0) ? udpSocketBufferSize : s; size_t listSize = listener.size(); if (myDetectorType == JUNGFRAU && (int)listSize != numUDPInterfaces) { - FILE_LOG(logERROR) << "Number of Interfaces " << numUDPInterfaces - << " do not match listener size " << listSize; - return FAIL; + throw sls::RuntimeError("Number of Interfaces " + std::to_string(numUDPInterfaces) + " do not match listener size " + std::to_string(listSize)); } for (unsigned int i = 0; i < listSize; ++i) { - if (listener[i]->CreateDummySocketForUDPSocketBufferSize(size) == FAIL) - return FAIL; + listener[i]->CreateDummySocketForUDPSocketBufferSize(size); } - - return OK; } int64_t Implementation::getActualUDPSocketBufferSize() const { @@ -1137,7 +1084,7 @@ bool Implementation::getDataStreamEnable() const { return dataStreamEnable; } -int Implementation::setDataStreamEnable(const bool enable) { +void Implementation::setDataStreamEnable(const bool enable) { if (dataStreamEnable != enable) { dataStreamEnable = enable; @@ -1164,14 +1111,13 @@ int Implementation::setDataStreamEnable(const bool enable) { } catch (...) { dataStreamer.clear(); dataStreamEnable = false; - return FAIL; + throw sls::RuntimeError("Could not set data stream enable."); } } SetThreadPriorities(); } } FILE_LOG(logINFO) << "Data Send to Gui: " << dataStreamEnable; - return OK; } uint32_t Implementation::getStreamingFrequency() const { @@ -1179,12 +1125,11 @@ uint32_t Implementation::getStreamingFrequency() const { return streamingFrequency; } -int Implementation::setStreamingFrequency(const uint32_t freq) { +void Implementation::setStreamingFrequency(const uint32_t freq) { if (streamingFrequency != freq) { streamingFrequency = freq; } FILE_LOG(logINFO) << "Streaming Frequency: " << streamingFrequency; - return OK; } uint32_t Implementation::getStreamingTimer() const { @@ -1307,7 +1252,7 @@ uint32_t Implementation::getNumberofAnalogSamples() const { return numberOfAnalogSamples; } -int Implementation::setNumberofAnalogSamples(const uint32_t i) { +void Implementation::setNumberofAnalogSamples(const uint32_t i) { if (numberOfAnalogSamples != i) { numberOfAnalogSamples = i; @@ -1318,13 +1263,11 @@ int Implementation::setNumberofAnalogSamples(const uint32_t i) { for (const auto &it : dataProcessor) it->SetPixelDimension(); - if (SetupFifoStructure() == FAIL) - return FAIL; + SetupFifoStructure(); } FILE_LOG(logINFO) << "Number of Analog Samples: " << numberOfAnalogSamples; FILE_LOG(logINFO) << "Packets per Frame: " << (generalData->packetsPerFrame); - return OK; } uint32_t Implementation::getNumberofDigitalSamples() const { @@ -1332,7 +1275,7 @@ uint32_t Implementation::getNumberofDigitalSamples() const { return numberOfDigitalSamples; } -int Implementation::setNumberofDigitalSamples(const uint32_t i) { +void Implementation::setNumberofDigitalSamples(const uint32_t i) { if (numberOfDigitalSamples != i) { numberOfDigitalSamples = i; @@ -1343,14 +1286,12 @@ int Implementation::setNumberofDigitalSamples(const uint32_t i) { for (const auto &it : dataProcessor) it->SetPixelDimension(); - if (SetupFifoStructure() == FAIL) - return FAIL; + SetupFifoStructure(); } FILE_LOG(logINFO) << "Number of Digital Samples: " << numberOfDigitalSamples; FILE_LOG(logINFO) << "Packets per Frame: " << (generalData->packetsPerFrame); - return OK; } uint32_t Implementation::getDynamicRange() const { @@ -1358,7 +1299,7 @@ uint32_t Implementation::getDynamicRange() const { return dynamicRange; } -int Implementation::setDynamicRange(const uint32_t i) { +void Implementation::setDynamicRange(const uint32_t i) { if (dynamicRange != i) { dynamicRange = i; @@ -1369,12 +1310,10 @@ int Implementation::setDynamicRange(const uint32_t i) { // to update npixelsx, npixelsy in file writer for (const auto &it : dataProcessor) it->SetPixelDimension(); - if (SetupFifoStructure() == FAIL) - return FAIL; + SetupFifoStructure(); } } FILE_LOG(logINFO) << "Dynamic Range: " << dynamicRange; - return OK; } slsDetectorDefs::ROI Implementation::getROI() const { @@ -1382,7 +1321,7 @@ slsDetectorDefs::ROI Implementation::getROI() const { return roi; } -int Implementation::setROI(slsDetectorDefs::ROI arg) { +void Implementation::setROI(slsDetectorDefs::ROI arg) { if (roi.xmin != arg.xmin || roi.xmax != arg.xmax) { roi.xmin = arg.xmin; roi.xmax = arg.xmax; @@ -1392,14 +1331,12 @@ int Implementation::setROI(slsDetectorDefs::ROI arg) { framesPerFile = generalData->maxFramesPerFile; for (const auto &it : dataProcessor) it->SetPixelDimension(); - if (SetupFifoStructure() == FAIL) - return FAIL; + SetupFifoStructure(); } FILE_LOG(logINFO) << "ROI: [" << roi.xmin << ", " << roi.xmax << "]";; FILE_LOG(logINFO) << "Packets per Frame: " << (generalData->packetsPerFrame); - return OK; } bool Implementation::getTenGigaEnable() const { @@ -1407,7 +1344,7 @@ bool Implementation::getTenGigaEnable() const { return tengigaEnable; } -int Implementation::setTenGigaEnable(const bool b) { +void Implementation::setTenGigaEnable(const bool b) { if (tengigaEnable != b) { tengigaEnable = b; // side effects @@ -1427,13 +1364,11 @@ int Implementation::setTenGigaEnable(const bool b) { break; } - if (SetupFifoStructure() == FAIL) - return FAIL; + SetupFifoStructure(); } FILE_LOG(logINFO) << "Ten Giga: " << (tengigaEnable ? "enabled" : "disabled"); FILE_LOG(logINFO) << "Packets per Frame: " << (generalData->packetsPerFrame); - return OK; } int Implementation::getFlippedDataX() const { @@ -1465,7 +1400,7 @@ bool Implementation::getGapPixelsEnable() const { return gapPixelsEnable; } -int Implementation::setGapPixelsEnable(const bool b) { +void Implementation::setGapPixelsEnable(const bool b) { if (gapPixelsEnable != b) { gapPixelsEnable = b; @@ -1473,11 +1408,9 @@ int Implementation::setGapPixelsEnable(const bool b) { generalData->SetGapPixelsEnable(b, dynamicRange, quadEnable); for (const auto &it : dataProcessor) it->SetPixelDimension(); - if (SetupFifoStructure() == FAIL) - return FAIL; + SetupFifoStructure(); } FILE_LOG(logINFO) << "Gap Pixels Enable: " << gapPixelsEnable; - return OK; } bool Implementation::getQuad() const { @@ -1485,7 +1418,7 @@ bool Implementation::getQuad() const { return quadEnable; } -int Implementation::setQuad(const bool b) { +void Implementation::setQuad(const bool b) { if (quadEnable != b) { quadEnable = b; @@ -1493,8 +1426,7 @@ int Implementation::setQuad(const bool b) { // to update npixelsx, npixelsy in file writer for (const auto &it : dataProcessor) it->SetPixelDimension(); - if (SetupFifoStructure() == FAIL) - return FAIL; + SetupFifoStructure(); if (!quadEnable) { for (const auto &it : dataStreamer) { @@ -1513,7 +1445,6 @@ int Implementation::setQuad(const bool b) { } } FILE_LOG(logINFO) << "Quad Enable: " << quadEnable; - return OK; } bool Implementation::getActivate() const { @@ -1557,7 +1488,7 @@ Implementation::getReadoutMode() const { return readoutType; } -int Implementation::setReadoutMode(const readoutMode f) { +void Implementation::setReadoutMode(const readoutMode f) { if (readoutType != f) { readoutType = f; @@ -1568,14 +1499,12 @@ int Implementation::setReadoutMode(const readoutMode f) { tengigaEnable, readoutType); for (const auto &it : dataProcessor) it->SetPixelDimension(); - if (SetupFifoStructure() == FAIL) - return FAIL; + SetupFifoStructure(); } FILE_LOG(logINFO) << "Readout Mode: " << sls::ToString(f); FILE_LOG(logINFO) << "Packets per Frame: " << (generalData->packetsPerFrame); - return OK; } uint32_t Implementation::getADCEnableMask() const { @@ -1583,7 +1512,7 @@ uint32_t Implementation::getADCEnableMask() const { return adcEnableMaskOneGiga; } -int Implementation::setADCEnableMask(uint32_t mask) { +void Implementation::setADCEnableMask(uint32_t mask) { if (adcEnableMaskOneGiga != mask) { adcEnableMaskOneGiga = mask; @@ -1594,15 +1523,13 @@ int Implementation::setADCEnableMask(uint32_t mask) { for (const auto &it : dataProcessor) it->SetPixelDimension(); - if (SetupFifoStructure() == FAIL) - return FAIL; + SetupFifoStructure(); } FILE_LOG(logINFO) << "ADC Enable Mask for 1Gb mode: 0x" << std::hex << adcEnableMaskOneGiga << std::dec; FILE_LOG(logINFO) << "Packets per Frame: " << (generalData->packetsPerFrame); - return OK; } uint32_t Implementation::getTenGigaADCEnableMask() const { @@ -1610,7 +1537,7 @@ uint32_t Implementation::getTenGigaADCEnableMask() const { return adcEnableMaskTenGiga; } -int Implementation::setTenGigaADCEnableMask(uint32_t mask) { +void Implementation::setTenGigaADCEnableMask(uint32_t mask) { if (adcEnableMaskTenGiga != mask) { adcEnableMaskTenGiga = mask; @@ -1621,15 +1548,13 @@ int Implementation::setTenGigaADCEnableMask(uint32_t mask) { for (const auto &it : dataProcessor) it->SetPixelDimension(); - if (SetupFifoStructure() == FAIL) - return FAIL; + SetupFifoStructure(); } FILE_LOG(logINFO) << "ADC Enable Mask for 10Gb mode: 0x" << std::hex << adcEnableMaskTenGiga << std::dec; FILE_LOG(logINFO) << "Packets per Frame: " << (generalData->packetsPerFrame); - return OK; } std::vector Implementation::getDbitList() const { diff --git a/slsReceiverSoftware/src/Listener.cpp b/slsReceiverSoftware/src/Listener.cpp index 8c0ae5764..7ef2f9e88 100755 --- a/slsReceiverSoftware/src/Listener.cpp +++ b/slsReceiverSoftware/src/Listener.cpp @@ -55,9 +55,7 @@ Listener::Listener(int ind, detectorType dtype, Fifo* f, std::atomic* numFramesStatistic(0), oddStartingPacket(true) { - if(ThreadObject::CreateThread() == FAIL) - throw sls::RuntimeError("Could not create listener thread"); - + ThreadObject::CreateThread(); FILE_LOG(logDEBUG) << "Listener " << ind << " created"; } @@ -155,19 +153,20 @@ void Listener::SetGeneralData(GeneralData* g) { } -int Listener::SetThreadPriority(int priority) { +void Listener::SetThreadPriority(int priority) { struct sched_param param; param.sched_priority = priority; - if (pthread_setschedparam(thread, SCHED_FIFO, ¶m) == EPERM) - return FAIL; + if (pthread_setschedparam(thread, SCHED_FIFO, ¶m) == EPERM) { + throw sls::RuntimeError("Could not prioritize listener threads. " + "(No Root Privileges?)"); + } FILE_LOG(logINFO) << "Listener Thread Priority set to " << priority; - return OK; } -int Listener::CreateUDPSockets() { +void Listener::CreateUDPSockets() { if (!(*activated)) { - return OK; + return; } //if eth is mistaken with ip address @@ -186,8 +185,7 @@ int Listener::CreateUDPSockets() { *udpSocketBufferSize); FILE_LOG(logINFO) << index << ": UDP port opened at port " << *udpPortNumber; } catch (...) { - FILE_LOG(logERROR) << "Could not create UDP socket on port " << *udpPortNumber; - return FAIL; + throw sls::RuntimeError("Could not create UDP socket on port "+ std::to_string(*udpPortNumber)); } udpSocketAlive = true; @@ -195,8 +193,6 @@ int Listener::CreateUDPSockets() { // doubled due to kernel bookkeeping (could also be less due to permissions) *actualUDPSocketBufferSize = udpSocket->getActualUDPSocketBufferSize(); - - return OK; } @@ -216,12 +212,12 @@ void Listener::ShutDownUDPSocket() { } -int Listener::CreateDummySocketForUDPSocketBufferSize(int64_t s) { +void Listener::CreateDummySocketForUDPSocketBufferSize(int64_t s) { FILE_LOG(logINFO) << "Testing UDP Socket Buffer size " << s << " with test port " << *udpPortNumber; if (!(*activated)) { *actualUDPSocketBufferSize = (s*2); - return OK; + return; } int64_t temp = *udpSocketBufferSize; @@ -247,12 +243,8 @@ int Listener::CreateDummySocketForUDPSocketBufferSize(int64_t s) { } } catch (...) { - FILE_LOG(logERROR) << "Could not create a test UDP socket on port " << *udpPortNumber; - return FAIL; + throw sls::RuntimeError("Could not create a test UDP socket on port " + std::to_string(*udpPortNumber)); } - - - return OK; } void Listener::SetHardCodedPosition(uint16_t r, uint16_t c) { diff --git a/slsReceiverSoftware/src/ThreadObject.cpp b/slsReceiverSoftware/src/ThreadObject.cpp index 47186fcd1..69e8dfca7 100755 --- a/slsReceiverSoftware/src/ThreadObject.cpp +++ b/slsReceiverSoftware/src/ThreadObject.cpp @@ -48,22 +48,18 @@ void ThreadObject::DestroyThread() { } -int ThreadObject::CreateThread() { - if(alive){ - FILE_LOG(logERROR) << "Cannot create thread " << index << ". Already alive"; - return FAIL; +void ThreadObject::CreateThread() { + if (alive) { + throw sls::RuntimeError("Cannot create " + GetType() + " thread " + std::to_string(index) + ". Already alive"); } sem_init(&semaphore,1,0); killThread = false; - if(pthread_create(&thread, nullptr,StartThread, (void*) this)){ - FILE_LOG(logERROR) << "Could not create " << GetType() << " thread with index " << index; - return FAIL; + if (pthread_create(&thread, nullptr,StartThread, (void*) this)){ + throw sls::RuntimeError("Could not create " + GetType() + " thread with index " + std::to_string(index)); } alive = true; FILE_LOG(logDEBUG) << GetType() << " thread " << index << " created successfully."; - - return OK; } From 2ece6b945e5e33da4d5bf7e1bca5a467af709cb3 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Fri, 29 Nov 2019 11:09:41 +0100 Subject: [PATCH 2/4] rxr: warnings shouldnt throw exception --- .../bin/eigerDetectorServer_developer | Bin 341541 -> 342755 bytes slsReceiverSoftware/src/ClientInterface.cpp | 4 ++-- slsReceiverSoftware/src/DataProcessor.cpp | 9 ++++++--- slsReceiverSoftware/src/DataStreamer.cpp | 9 ++++++--- slsReceiverSoftware/src/Implementation.cpp | 7 ------- slsReceiverSoftware/src/Listener.cpp | 9 ++++++--- slsSupportLib/include/versionAPI.h | 2 +- 7 files changed, 21 insertions(+), 19 deletions(-) diff --git a/slsDetectorServers/eigerDetectorServer/bin/eigerDetectorServer_developer b/slsDetectorServers/eigerDetectorServer/bin/eigerDetectorServer_developer index e41ce7dce3341a9638532358ed862542f29c5f20..cf12b2dee086457c5bab05ae77143411a438c62d 100755 GIT binary patch delta 82920 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 TtJ(Nwttix0o8yVi7MlMLr*LDX delta 78693 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 G`u_$^x~jnd diff --git a/slsReceiverSoftware/src/ClientInterface.cpp b/slsReceiverSoftware/src/ClientInterface.cpp index 1d82296b4..8a213c074 100755 --- a/slsReceiverSoftware/src/ClientInterface.cpp +++ b/slsReceiverSoftware/src/ClientInterface.cpp @@ -268,7 +268,7 @@ void ClientInterface::VerifyLock() { void ClientInterface::VerifyIdle(Interface &socket) { if (impl()->getStatus() != IDLE) { std::ostringstream oss; - oss << "Can not execute " << GetFunctionNameFromEnum((enum detFuncs)fnum) + oss << "Can not execute " << getFunctionNameFromEnum((enum detFuncs)fnum) << " when receiver is not idle"; throw sls::SocketError(oss.str()); } @@ -286,7 +286,7 @@ int ClientInterface::exec_command(Interface &socket) { if (!pipe) { throw RuntimeError("Executing Command failed\n"); } else { - while (!feof(pipe.Get())) { + while (!feof(pipe.get())) { if (fgets(temp.data(), tempsize, pipe.get()) != nullptr) sresult += temp.data(); } diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index 7d74bb647..98907e54d 100755 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -159,10 +159,13 @@ void DataProcessor::SetThreadPriority(int priority) { struct sched_param param; param.sched_priority = priority; if (pthread_setschedparam(thread, SCHED_FIFO, ¶m) == EPERM) { - throw sls::RuntimeError("Could not prioritize dataprocessing threads. " - "(No Root Privileges?)"); + if (!index) { + FILE_LOG(logWARNING) << "Could not prioritize dataprocessing thread. " + "(No Root Privileges?)"; + } + } else { + FILE_LOG(logINFO) << "Priorities set - DataProcessor: " << priority; } - FILE_LOG(logINFO) << "Processor Thread Priority set to " << priority; } diff --git a/slsReceiverSoftware/src/DataStreamer.cpp b/slsReceiverSoftware/src/DataStreamer.cpp index f79c4010a..cd4a95302 100755 --- a/slsReceiverSoftware/src/DataStreamer.cpp +++ b/slsReceiverSoftware/src/DataStreamer.cpp @@ -108,10 +108,13 @@ void DataStreamer::SetThreadPriority(int priority) { struct sched_param param; param.sched_priority = priority; if (pthread_setschedparam(thread, SCHED_FIFO, ¶m) == EPERM) { - throw sls::RuntimeError("Could not prioritize datastreaming threads. " - "(No Root Privileges?)"); + if (!index) { + FILE_LOG(logWARNING) << "Could not prioritize datastreaming thread. " + "(No Root Privileges?)"; + } + } else { + FILE_LOG(logINFO) << "Priorities set - DataStreamer: " << priority; } - FILE_LOG(logINFO) << "Streamer Thread Priority set to " << priority; } void DataStreamer::SetNumberofDetectors(int* nd) { diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index 4cfc103ad..e8dd2d98d 100755 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -161,16 +161,9 @@ void Implementation::SetLocalNetworkParameters() { void Implementation::SetThreadPriorities() { FILE_LOG(logDEBUG3) << __SHORT_AT__ << " called"; - for (const auto &it : listener) { it->SetThreadPriority(LISTENER_PRIORITY); } - std::ostringstream osfn; - osfn << "Priorities set - " - "Listener:" - << LISTENER_PRIORITY; - - FILE_LOG(logINFO) << osfn.str(); } void Implementation::SetupFifoStructure() { diff --git a/slsReceiverSoftware/src/Listener.cpp b/slsReceiverSoftware/src/Listener.cpp index 7ef2f9e88..88957077c 100755 --- a/slsReceiverSoftware/src/Listener.cpp +++ b/slsReceiverSoftware/src/Listener.cpp @@ -157,10 +157,13 @@ void Listener::SetThreadPriority(int priority) { struct sched_param param; param.sched_priority = priority; if (pthread_setschedparam(thread, SCHED_FIFO, ¶m) == EPERM) { - throw sls::RuntimeError("Could not prioritize listener threads. " - "(No Root Privileges?)"); + if (!index) { + FILE_LOG(logWARNING) << "Could not prioritize listener thread. " + "(No Root Privileges?)"; + } + } else { + FILE_LOG(logINFO) << "Priorities set - Listener: " << priority; } - FILE_LOG(logINFO) << "Listener Thread Priority set to " << priority; } void Listener::CreateUDPSockets() { diff --git a/slsSupportLib/include/versionAPI.h b/slsSupportLib/include/versionAPI.h index e0d66833f..2f676c084 100644 --- a/slsSupportLib/include/versionAPI.h +++ b/slsSupportLib/include/versionAPI.h @@ -4,9 +4,9 @@ #define APIRECEIVER 0x190722 #define APIGUI 0x190723 #define APIMOENCH 0x190820 -#define APIEIGER 0x191111 #define APIGOTTHARD2 0x191127 #define APIMYTHEN3 0x191127 #define APICTB 0x191127 #define APIGOTTHARD 0x191127 #define APIJUNGFRAU 0x191127 +#define APIEIGER 0x191129 From 16bec25b0c3d70624f590c56328446b5b4ca6ecc Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Fri, 29 Nov 2019 15:17:41 +0100 Subject: [PATCH 3/4] rxr: pthread to thread and created and destroyed tcp thread in constructor and destructor --- slsReceiverSoftware/include/ClientInterface.h | 46 ++-- slsReceiverSoftware/src/ClientInterface.cpp | 206 ++++++++---------- 2 files changed, 108 insertions(+), 144 deletions(-) diff --git a/slsReceiverSoftware/include/ClientInterface.h b/slsReceiverSoftware/include/ClientInterface.h index ca7a3c7a5..2df26832f 100755 --- a/slsReceiverSoftware/include/ClientInterface.h +++ b/slsReceiverSoftware/include/ClientInterface.h @@ -6,7 +6,8 @@ class MySocketTCP; class ServerInterface; - +#include +#include class ClientInterface : private virtual slsDetectorDefs { private: @@ -38,17 +39,16 @@ class ClientInterface : private virtual slsDetectorDefs { void *arg); private: - void startTCPSocket(); - void stopTCPSocket(); - static void *startTCPServerThread(void *this_pointer); void startTCPServer(); - - int function_table(); - int decode_function(sls::ServerInterface2 &socket); + int functionTable(); + int decodeFunction(sls::ServerInterface2 &socket); void functionNotImplemented(); void modeNotImplemented(const std::string& modename, int mode); template void validate(T arg, T retval, std::string modename, numberMode hex); + void verifyLock(); + void verifyIdle(sls::ServerInterface2 &socket); + int exec_command(sls::ServerInterface2 &socket); int exit_server(sls::ServerInterface2 &socket); @@ -120,20 +120,27 @@ class ClientInterface : private virtual slsDetectorDefs { int set_num_interfaces(sls::ServerInterface2 &socket); int set_adc_mask_10g(sls::ServerInterface2 &socket); + Implementation *impl() { + if (receiver != nullptr) { + return receiver.get(); + } else { + throw sls::SocketError( + "Receiver not set up. Please use rx_hostname first.\n"); + } + } + detectorType myDetectorType; std::unique_ptr receiver{nullptr}; int (ClientInterface::*flist[NUM_REC_FUNCTIONS])( sls::ServerInterface2 &socket); int ret{OK}; int fnum{-1}; - /** Lock Status if server locked to a client */ - int lockStatus{0}; + int lockedByClient{0}; + int portNumber{0}; + std::atomic killTcpThread{false}; + std::unique_ptr tcpThread; - int killTCPServerThread{0}; - pthread_t TCPServer_thread; - bool tcpThreadCreated{false}; - int portNumber; //***callback parameters*** @@ -149,17 +156,4 @@ class ClientInterface : private virtual slsDetectorDefs { protected: std::unique_ptr server{nullptr}; - - private: - void VerifyLock(); - void VerifyIdle(sls::ServerInterface2 &socket); - - Implementation *impl() { - if (receiver != nullptr) { - return receiver.get(); - } else { - throw sls::SocketError( - "Receiver not set up. Please use rx_hostname first.\n"); - } - } }; diff --git a/slsReceiverSoftware/src/ClientInterface.cpp b/slsReceiverSoftware/src/ClientInterface.cpp index 8a213c074..c56e7ec0a 100755 --- a/slsReceiverSoftware/src/ClientInterface.cpp +++ b/slsReceiverSoftware/src/ClientInterface.cpp @@ -20,38 +20,24 @@ using sls::RuntimeError; using sls::SocketError; using Interface = sls::ServerInterface2; -ClientInterface::~ClientInterface() { stopTCPSocket(); } +ClientInterface::~ClientInterface() { + killTcpThread = true; + // shut down tcp sockets + if (server.get() != nullptr) { + FILE_LOG(logINFO) << "Shutting down TCP Socket on port " << portNumber; + server->shutDownSocket(); + FILE_LOG(logDEBUG) << "TCP Socket closed on port " << portNumber; + } + // shut down tcp thread + tcpThread->join(); +} ClientInterface::ClientInterface(int portNumber) - : myDetectorType(GOTTHARD), portNumber(portNumber > 0 ? portNumber : DEFAULT_PORTNO + 2) { - function_table(); - startTCPSocket(); -} - -void ClientInterface::startTCPSocket() { - FILE_LOG(logDEBUG) << "Creating TCP Server Thread"; - killTCPServerThread = 0; - if (pthread_create(&TCPServer_thread, nullptr, startTCPServerThread, - (void *)this)) { - throw RuntimeError("Could not create TCP Server thread"); - } - tcpThreadCreated = true; - FILE_LOG(logDEBUG) << "TCP Server thread created successfully."; -} - -void ClientInterface::stopTCPSocket() { - if (tcpThreadCreated) { - FILE_LOG(logINFO) << "Shutting down TCP Socket on port " << portNumber; - killTCPServerThread = 1; - if (server) - server->shutDownSocket(); - FILE_LOG(logDEBUG) << "TCP Socket closed on port " << portNumber; - pthread_join(TCPServer_thread, nullptr); - tcpThreadCreated = false; - killTCPServerThread = 0; - FILE_LOG(logDEBUG) << "Exiting TCP Server Thread on port " - << portNumber; - } + : myDetectorType(GOTTHARD), + portNumber(portNumber > 0 ? portNumber : DEFAULT_PORTNO + 2) { + functionTable(); + // start up tcp thread + tcpThread = sls::make_unique(&ClientInterface::startTCPServer, this); } int64_t ClientInterface::getReceiverVersion() { return APIRECEIVER; } @@ -81,14 +67,8 @@ void ClientInterface::registerCallBackRawDataModifyReady( pRawDataReady = arg; } -void *ClientInterface::startTCPServerThread(void *this_pointer) { - ((ClientInterface *)this_pointer)->startTCPServer(); - return this_pointer; -} - void ClientInterface::startTCPServer() { - FILE_LOG(logINFOBLUE) << "Created [ TCP server Tid: " << syscall(SYS_gettid) - << "]"; + FILE_LOG(logINFOBLUE) << "Created [ TCP server Tid: " << syscall(SYS_gettid) << "]"; FILE_LOG(logINFO) << "SLS Receiver starting TCP Server on port " << portNumber << '\n'; server = sls::make_unique(portNumber); @@ -97,8 +77,8 @@ void ClientInterface::startTCPServer() { try { auto socket = server->accept(); try { - VerifyLock(); - ret = decode_function(socket); + verifyLock(); + ret = decodeFunction(socket); } catch (const RuntimeError &e) { // We had an error needs to be sent to client char mess[MAX_STR_LENGTH]{}; @@ -106,37 +86,27 @@ void ClientInterface::startTCPServer() { socket.Send(FAIL); socket.Send(mess); } - // if tcp command was to exit server if (ret == GOODBYE) { - FILE_LOG(logINFO) << "Shutting down UDP Socket"; - if (receiver) { - receiver->shutDownUDPSockets(); - } - FILE_LOG(logINFOBLUE) - << "Exiting [ TCP server Tid: " << syscall(SYS_gettid) - << "]"; - pthread_exit(nullptr); + break; } } catch (const RuntimeError &e) { FILE_LOG(logERROR) << "Accept failed"; } - - // if user entered exit - if (killTCPServerThread) { - if (ret != GOODBYE) { - if (receiver) { - receiver->shutDownUDPSockets(); - } - } - FILE_LOG(logINFOBLUE) - << "Exiting [ TCP server Tid: " << syscall(SYS_gettid) << "]"; - pthread_exit(nullptr); + // destructor to kill this thread + if (killTcpThread) { + break; } } + + if (receiver) { + receiver->shutDownUDPSockets(); + } + FILE_LOG(logINFOBLUE) << "Exiting [ TCP server Tid: " << syscall(SYS_gettid) << "]"; } + // clang-format off -int ClientInterface::function_table(){ +int ClientInterface::functionTable(){ flist[F_EXEC_RECEIVER_COMMAND] = &ClientInterface::exec_command; flist[F_EXIT_RECEIVER] = &ClientInterface::exit_server; flist[F_LOCK_RECEIVER] = &ClientInterface::lock_receiver; @@ -207,35 +177,35 @@ int ClientInterface::function_table(){ for (int i = NUM_DET_FUNCTIONS + 1; i < NUM_REC_FUNCTIONS ; i++) { - // FILE_LOG(logDEBUG1) << "function fnum: " << i << " (" << - // getFunctionNameFromEnum((enum detFuncs)i) << ") located at " << flist[i]; + FILE_LOG(logDEBUG1) << "function fnum: " << i << " (" << + getFunctionNameFromEnum((enum detFuncs)i) << ") located at " << flist[i]; } return OK; } // clang-format on -int ClientInterface::decode_function(Interface &socket) { +int ClientInterface::decodeFunction(Interface &socket) { ret = FAIL; socket.Receive(fnum); if (fnum <= NUM_DET_FUNCTIONS || fnum >= NUM_REC_FUNCTIONS) { throw RuntimeError("Unrecognized Function enum " + std::to_string(fnum) + "\n"); } else { - // FILE_LOG(logDEBUG1) << "calling function fnum: " << fnum << " (" - // << getFunctionNameFromEnum((enum detFuncs)fnum) - // << ")"; + FILE_LOG(logDEBUG1) << "calling function fnum: " << fnum << " (" + << getFunctionNameFromEnum((enum detFuncs)fnum) + << ")"; ret = (this->*flist[fnum])(socket); - // FILE_LOG(logDEBUG1) - // << "Function " << getFunctionNameFromEnum((enum detFuncs)fnum) - // << " finished"; + FILE_LOG(logDEBUG1) + << "Function " << getFunctionNameFromEnum((enum detFuncs)fnum) + << " finished"; } return ret; } void ClientInterface::functionNotImplemented() { std::ostringstream os; - // os << "Function: " << getFunctionNameFromEnum((enum detFuncs)fnum) - // << ", is is not implemented for this detector"; + os << "Function: " << getFunctionNameFromEnum((enum detFuncs)fnum) + << ", is is not implemented for this detector"; throw RuntimeError(os.str()); } @@ -259,13 +229,13 @@ void ClientInterface::validate(T arg, T retval, std::string modename, } } -void ClientInterface::VerifyLock() { - if (lockStatus && server->getThisClient() != server->getLockedBy()) { +void ClientInterface::verifyLock() { + if (lockedByClient && server->getThisClient() != server->getLockedBy()) { throw sls::SocketError("Receiver locked\n"); } } -void ClientInterface::VerifyIdle(Interface &socket) { +void ClientInterface::verifyIdle(Interface &socket) { if (impl()->getStatus() != IDLE) { std::ostringstream oss; oss << "Can not execute " << getFunctionNameFromEnum((enum detFuncs)fnum) @@ -306,15 +276,15 @@ int ClientInterface::lock_receiver(Interface &socket) { auto lock = socket.Receive(); FILE_LOG(logDEBUG1) << "Locking Server to " << lock; if (lock >= 0) { - if (!lockStatus || (server->getLockedBy() == server->getThisClient())) { - lockStatus = lock; + if (!lockedByClient || (server->getLockedBy() == server->getThisClient())) { + lockedByClient = lock; lock ? server->setLockedBy(server->getThisClient()) : server->setLockedBy(sls::IpAddr{}); } else { throw RuntimeError("Receiver locked\n"); } } - return socket.sendResult(lockStatus); + return socket.sendResult(lockedByClient); } int ClientInterface::get_last_client_ip(Interface &socket) { @@ -458,7 +428,7 @@ int ClientInterface::set_detector_type(Interface &socket) { // if object exists, verify unlocked and idle, else only verify lock // (connecting first time) if (receiver != nullptr) { - VerifyIdle(socket); + verifyIdle(socket); } switch (arg) { case GOTTHARD: @@ -504,7 +474,7 @@ int ClientInterface::set_detector_hostname(Interface &socket) { socket.Receive(hostname); if (strlen(hostname) != 0) { - VerifyIdle(socket); + verifyIdle(socket); impl()->setDetectorHostname(hostname); } auto s = impl()->getDetectorHostname(); @@ -524,7 +494,7 @@ int ClientInterface::set_roi(Interface &socket) { if (myDetectorType != GOTTHARD) functionNotImplemented(); - VerifyIdle(socket); + verifyIdle(socket); try { impl()->setROI(arg); } catch(const RuntimeError &e) { @@ -601,7 +571,7 @@ int ClientInterface::set_subdeadtime(Interface &socket) { int ClientInterface::set_dynamic_range(Interface &socket) { auto dr = socket.Receive(); if (dr >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting dynamic range: " << dr; bool exists = false; switch(myDetectorType) { @@ -641,7 +611,7 @@ int ClientInterface::set_dynamic_range(Interface &socket) { int ClientInterface::set_streaming_frequency(Interface &socket) { auto index = socket.Receive(); if (index >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting streaming frequency: " << index; impl()->setStreamingFrequency(index); } @@ -720,7 +690,7 @@ int ClientInterface::set_file_name(Interface &socket) { int ClientInterface::set_file_index(Interface &socket) { auto index = socket.Receive(); if (index >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting file index: " << index; impl()->setFileIndex(index); } @@ -757,7 +727,7 @@ int ClientInterface::get_frames_caught(Interface &socket) { int ClientInterface::enable_file_write(Interface &socket) { auto enable = socket.Receive(); if (enable >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting File write enable:" << enable; impl()->setFileWriteEnable(enable); } @@ -770,7 +740,7 @@ int ClientInterface::enable_file_write(Interface &socket) { int ClientInterface::enable_master_file_write(Interface &socket) { auto enable = socket.Receive(); if (enable >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting Master File write enable:" << enable; impl()->setMasterFileWriteEnable(enable); } @@ -783,7 +753,7 @@ int ClientInterface::enable_master_file_write(Interface &socket) { int ClientInterface::enable_overwrite(Interface &socket) { auto index = socket.Receive(); if (index >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting File overwrite enable:" << index; impl()->setOverwriteEnable(index); } @@ -800,7 +770,7 @@ int ClientInterface::enable_tengiga(Interface &socket) { functionNotImplemented(); if (val >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting 10GbE:" << val; try { impl()->setTenGigaEnable(val); @@ -817,7 +787,7 @@ int ClientInterface::enable_tengiga(Interface &socket) { int ClientInterface::set_fifo_depth(Interface &socket) { auto value = socket.Receive(); if (value >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting fifo depth:" << value; try { impl()->setFifoDepth(value); @@ -837,7 +807,7 @@ int ClientInterface::set_activate(Interface &socket) { functionNotImplemented(); if (enable >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting activate:" << enable; impl()->setActivate(static_cast(enable)); } @@ -850,7 +820,7 @@ int ClientInterface::set_activate(Interface &socket) { int ClientInterface::set_data_stream_enable(Interface &socket) { auto index = socket.Receive(); if (index >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting data stream enable:" << index; try { impl()->setDataStreamEnable(index); @@ -867,7 +837,7 @@ int ClientInterface::set_data_stream_enable(Interface &socket) { int ClientInterface::set_streaming_timer(Interface &socket) { auto index = socket.Receive(); if (index >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting streaming timer:" << index; impl()->setStreamingTimer(index); } @@ -884,7 +854,7 @@ int ClientInterface::set_flipped_data(Interface &socket) { functionNotImplemented(); if (arg >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting flipped data:" << arg; impl()->setFlippedDataX(arg); } @@ -898,7 +868,7 @@ int ClientInterface::set_file_format(Interface &socket) { fileFormat f = GET_FILE_FORMAT; socket.Receive(f); if (f >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting file format:" << f; impl()->setFileFormat(f); } @@ -911,7 +881,7 @@ int ClientInterface::set_file_format(Interface &socket) { int ClientInterface::set_detector_posid(Interface &socket) { auto arg = socket.Receive(); if (arg >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting detector position id:" << arg; impl()->setDetectorPositionId(arg); } @@ -925,7 +895,7 @@ int ClientInterface::set_multi_detector_size(Interface &socket) { int arg[]{-1, -1}; socket.Receive(arg); if ((arg[0] > 0) && (arg[1] > 0)) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting multi detector size:" << arg[0] << "," << arg[1]; impl()->setMultiDetectorSize(arg); @@ -939,7 +909,7 @@ int ClientInterface::set_multi_detector_size(Interface &socket) { int ClientInterface::set_streaming_port(Interface &socket) { auto port = socket.Receive(); if (port >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting streaming port:" << port; impl()->setStreamingPort(port); } @@ -952,7 +922,7 @@ int ClientInterface::set_streaming_port(Interface &socket) { int ClientInterface::set_streaming_source_ip(Interface &socket) { sls::IpAddr arg = 0u; socket.Receive(arg); - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting streaming source ip:" << arg; impl()->setStreamingSourceIP(arg); sls::IpAddr retval = impl()->getStreamingSourceIP(); @@ -968,7 +938,7 @@ int ClientInterface::set_streaming_source_ip(Interface &socket) { int ClientInterface::set_silent_mode(Interface &socket) { auto value = socket.Receive(); if (value >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting silent mode:" << value; impl()->setSilentMode(value); } @@ -984,7 +954,7 @@ int ClientInterface::enable_gap_pixels(Interface &socket) { functionNotImplemented(); if (enable >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting gap pixels enable:" << enable; try { impl()->setGapPixelsEnable(static_cast(enable)); @@ -999,7 +969,7 @@ int ClientInterface::enable_gap_pixels(Interface &socket) { } int ClientInterface::restream_stop(Interface &socket) { - VerifyIdle(socket); + verifyIdle(socket); if (!impl()->getDataStreamEnable()) { throw RuntimeError( "Could not restream stop packet as data Streaming is disabled"); @@ -1014,7 +984,7 @@ int ClientInterface::set_additional_json_header(Interface &socket) { char arg[MAX_STR_LENGTH]{}; char retval[MAX_STR_LENGTH]{}; socket.Receive(arg); - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting additional json header: " << arg; impl()->setAdditionalJsonHeader(arg); sls::strcpy_safe(retval, impl()->getAdditionalJsonHeader().c_str()); @@ -1032,7 +1002,7 @@ int ClientInterface::get_additional_json_header(Interface &socket) { int ClientInterface::set_udp_socket_buffer_size(Interface &socket) { auto index = socket.Receive(); if (index >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting UDP Socket Buffer size: " << index; impl()->setUDPSocketBufferSize(index); } @@ -1055,7 +1025,7 @@ int ClientInterface::get_real_udp_socket_buffer_size( int ClientInterface::set_frames_per_file(Interface &socket) { auto index = socket.Receive(); if (index >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting frames per file: " << index; impl()->setFramesPerFile(index); } @@ -1096,7 +1066,7 @@ int ClientInterface::check_version_compatibility(Interface &socket) { int ClientInterface::set_discard_policy(Interface &socket) { auto index = socket.Receive(); if (index >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting frames discard policy: " << index; impl()->setFrameDiscardPolicy(static_cast(index)); } @@ -1109,7 +1079,7 @@ int ClientInterface::set_discard_policy(Interface &socket) { int ClientInterface::set_padding_enable(Interface &socket) { auto index = socket.Receive(); if (index >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting frames padding enable: " << index; impl()->setFramePaddingEnable(static_cast(index)); } @@ -1126,7 +1096,7 @@ int ClientInterface::set_deactivated_padding_enable( functionNotImplemented(); if (enable >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting deactivated padding enable: " << enable; impl()->setDeactivatedPadding(enable > 0); } @@ -1143,7 +1113,7 @@ int ClientInterface::set_readout_mode(Interface &socket) { functionNotImplemented(); if (arg >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting readout mode: " << arg; try { impl()->setReadoutMode(arg); @@ -1160,7 +1130,7 @@ int ClientInterface::set_readout_mode(Interface &socket) { int ClientInterface::set_adc_mask(Interface &socket) { auto arg = socket.Receive(); - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting 1Gb ADC enable mask: " << arg; try { impl()->setADCEnableMask(arg); @@ -1186,7 +1156,7 @@ int ClientInterface::set_dbit_list(Interface &socket) { FILE_LOG(logDEBUG1) << it << " "; } FILE_LOG(logDEBUG1) << "\n"; - VerifyIdle(socket); + verifyIdle(socket); impl()->setDbitList(args); return socket.Send(OK); } @@ -1201,7 +1171,7 @@ int ClientInterface::get_dbit_list(Interface &socket) { int ClientInterface::set_dbit_offset(Interface &socket) { auto arg = socket.Receive(); if (arg >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting Dbit offset: " << arg; impl()->setDbitOffset(arg); } @@ -1214,7 +1184,7 @@ int ClientInterface::set_dbit_offset(Interface &socket) { int ClientInterface::set_quad_type(Interface &socket) { auto quadEnable = socket.Receive(); if (quadEnable >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting quad:" << quadEnable; try { impl()->setQuad(quadEnable == 0 ? false : true); @@ -1231,7 +1201,7 @@ int ClientInterface::set_quad_type(Interface &socket) { int ClientInterface::set_read_n_lines(Interface &socket) { auto arg = socket.Receive(); if (arg >= 0) { - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting Read N Lines:" << arg; impl()->setReadNLines(arg); } @@ -1244,7 +1214,7 @@ int ClientInterface::set_read_n_lines(Interface &socket) { int ClientInterface::set_udp_ip(Interface &socket) { auto arg = socket.Receive(); - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logINFO) << "Received UDP IP: " << arg; // getting eth std::string eth = sls::IpToInterfaceName(arg.str()); @@ -1271,7 +1241,7 @@ int ClientInterface::set_udp_ip(Interface &socket) { int ClientInterface::set_udp_ip2(Interface &socket) { auto arg = socket.Receive(); - VerifyIdle(socket); + verifyIdle(socket); if (myDetectorType != JUNGFRAU) { throw RuntimeError("UDP Destination IP2 not implemented for this detector"); } @@ -1298,7 +1268,7 @@ int ClientInterface::set_udp_ip2(Interface &socket) { int ClientInterface::set_udp_port(Interface &socket) { auto arg = socket.Receive(); - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting UDP Port:" << arg; impl()->setUDPPortNumber(arg); return socket.Send(OK); @@ -1306,7 +1276,7 @@ int ClientInterface::set_udp_port(Interface &socket) { int ClientInterface::set_udp_port2(Interface &socket) { auto arg = socket.Receive(); - VerifyIdle(socket); + verifyIdle(socket); if (myDetectorType != JUNGFRAU && myDetectorType != EIGER) { throw RuntimeError("UDP Destination Port2 not implemented for this detector"); } @@ -1318,7 +1288,7 @@ int ClientInterface::set_udp_port2(Interface &socket) { int ClientInterface::set_num_interfaces(Interface &socket) { auto arg = socket.Receive(); arg = (arg > 1 ? 2 : 1); - VerifyIdle(socket); + verifyIdle(socket); if (myDetectorType != JUNGFRAU) { throw RuntimeError("Number of interfaces not implemented for this detector"); } @@ -1333,7 +1303,7 @@ int ClientInterface::set_num_interfaces(Interface &socket) { int ClientInterface::set_adc_mask_10g(Interface &socket) { auto arg = socket.Receive(); - VerifyIdle(socket); + verifyIdle(socket); FILE_LOG(logDEBUG1) << "Setting 10Gb ADC enable mask: " << arg; try { impl()->setTenGigaADCEnableMask(arg); From 1a8337540a649889825807373c7425c634aa2e56 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Fri, 29 Nov 2019 16:19:02 +0100 Subject: [PATCH 4/4] rxr: switched to threads for threadObject (from pthread), moved priorities to threadObject, mutex --- slsDetectorSoftware/src/multiSlsDetector.h | 1 - slsReceiverSoftware/include/DataProcessor.h | 12 --- slsReceiverSoftware/include/DataStreamer.h | 12 --- slsReceiverSoftware/include/HDF5File.h | 4 +- slsReceiverSoftware/include/Listener.h | 12 --- slsReceiverSoftware/include/ThreadObject.h | 83 +++------------- slsReceiverSoftware/src/DataProcessor.cpp | 21 +--- slsReceiverSoftware/src/DataStreamer.cpp | 20 +--- slsReceiverSoftware/src/HDF5File.cpp | 71 +++++--------- slsReceiverSoftware/src/Listener.cpp | 22 +---- slsReceiverSoftware/src/ThreadObject.cpp | 102 +++++++------------- 11 files changed, 75 insertions(+), 285 deletions(-) diff --git a/slsDetectorSoftware/src/multiSlsDetector.h b/slsDetectorSoftware/src/multiSlsDetector.h index e992658c9..a90d05e21 100755 --- a/slsDetectorSoftware/src/multiSlsDetector.h +++ b/slsDetectorSoftware/src/multiSlsDetector.h @@ -462,7 +462,6 @@ class multiSlsDetector : public virtual slsDetectorDefs { bool jointhread{false}; /** the data processing thread */ - // pthread_t dataProcessingThread; std::thread dataProcessingThread; /** detector data packed for the gui */ diff --git a/slsReceiverSoftware/include/DataProcessor.h b/slsReceiverSoftware/include/DataProcessor.h index ff0a430e8..7dbce1eb1 100755 --- a/slsReceiverSoftware/include/DataProcessor.h +++ b/slsReceiverSoftware/include/DataProcessor.h @@ -118,12 +118,6 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { */ void SetGeneralData(GeneralData* g); - /** - * Set thread priority - * @priority priority - */ - void SetThreadPriority(int priority); - /** * Set File Format * @param f file format @@ -199,12 +193,6 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { private: - /** - * Get Type - * @return type - */ - std::string GetType() override; - /** * Record First Index * @param fnum frame index to record diff --git a/slsReceiverSoftware/include/DataStreamer.h b/slsReceiverSoftware/include/DataStreamer.h index f341fa960..c3fdd8d22 100755 --- a/slsReceiverSoftware/include/DataStreamer.h +++ b/slsReceiverSoftware/include/DataStreamer.h @@ -79,12 +79,6 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject { */ void SetGeneralData(GeneralData* g); - /** - * Set thread priority - * @priority priority - */ - void SetThreadPriority(int priority); - /** * Set number of detectors * @param number of detectors in both dimensions @@ -119,12 +113,6 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject { private: - /** - * Get Type - * @return type - */ - std::string GetType(); - /** * Record First Index * @param fnum frame index to record diff --git a/slsReceiverSoftware/include/HDF5File.h b/slsReceiverSoftware/include/HDF5File.h index 5706ec126..722758cc0 100755 --- a/slsReceiverSoftware/include/HDF5File.h +++ b/slsReceiverSoftware/include/HDF5File.h @@ -17,6 +17,7 @@ #ifndef H5_NO_NAMESPACE using namespace H5; #endif +#include class HDF5File : private virtual slsDetectorDefs, public File, public HDF5FileStatic { @@ -130,9 +131,8 @@ class HDF5File : private virtual slsDetectorDefs, public File, public HDF5FileSt void UpdateDataType(); - /** mutex to update static items among objects (threads)*/ - static pthread_mutex_t Mutex; + static mutable std::mutex mutex; /** Master File handle */ static H5File* masterfd; diff --git a/slsReceiverSoftware/include/Listener.h b/slsReceiverSoftware/include/Listener.h index 2b72b64ec..423df0fa2 100755 --- a/slsReceiverSoftware/include/Listener.h +++ b/slsReceiverSoftware/include/Listener.h @@ -102,12 +102,6 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject { */ void SetGeneralData(GeneralData* g); - /** - * Set thread priority - * @priority priority - */ - void SetThreadPriority(int priority); - /** * Creates UDP Sockets */ @@ -136,12 +130,6 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject { private: - /** - * Get Type - * @return type - */ - std::string GetType() override; - /** * Record First Acquisition Index * @param fnum frame index to record diff --git a/slsReceiverSoftware/include/ThreadObject.h b/slsReceiverSoftware/include/ThreadObject.h index 6d68a8db4..cc9ffddf1 100755 --- a/slsReceiverSoftware/include/ThreadObject.h +++ b/slsReceiverSoftware/include/ThreadObject.h @@ -10,76 +10,27 @@ #include "sls_detector_defs.h" #include "logger.h" -#include + #include #include +#include +#include class ThreadObject : private virtual slsDetectorDefs { public: - /** - * Constructor - * @param ind self index - */ - ThreadObject(int ind); - - /** - * Destructor - * if alive, destroys thread - */ + ThreadObject(int threadIndex, std::string threadType); virtual ~ThreadObject(); - - /** - * Print all member values - */ - void PrintMembers(); - - - /** - * Get Type - * @return type - */ - virtual std::string GetType() = 0; - - /** - * Returns if the thread is currently running - * @returns true if thread is running, else false - */ virtual bool IsRunning() = 0; - - /** - * What is really being executed in the thread - */ - virtual void ThreadExecution() = 0; - - /** - * Post semaphore so thread can continue & start an acquisition - */ void Continue(); + void SetThreadPriority(int priority); protected: - - /** - * Destroy thread, semaphore and resets alive and killThread - */ - void DestroyThread(); - - /** - * Create Thread, sets semaphore, alive and killThread - */ - void CreateThread(); - + virtual void ThreadExecution() = 0; private: - /** - * Static function using pointer from argument to call RunningThread() - * @param thisPointer pointer to an object of ThreadObject - */ - static void* StartThread(void *thisPointer); - - /** - * Actual Thread called: An infinite while loop in which, + * Thread called: An infinite while loop in which, * semaphore starts executing its contents as long RunningMask is satisfied * Then it exits the thread on its own if killThread is true */ @@ -87,22 +38,10 @@ class ThreadObject : private virtual slsDetectorDefs { protected: - /** Self Index */ - int index; - - /** Thread is alive/dead */ - volatile bool alive; - - /** Variable monitored by thread to kills itself */ - volatile bool killThread; - - /** Thread variable */ - pthread_t thread; - - /** Semaphore to synchonize starting of each run */ + int index{0}; + std::string type; + std::atomic killThread{false}; + std::unique_ptr threadObject; sem_t semaphore; - - - }; diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index 98907e54d..f81673b55 100755 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -30,7 +30,7 @@ DataProcessor::DataProcessor(int ind, detectorType dtype, Fifo* f, bool* fp, bool* act, bool* depaden, bool* sm, bool* qe, std::vector * cdl, int* cdo, int* cad) : - ThreadObject(ind), + ThreadObject(ind, TypeName), runningFlag(false), generalData(nullptr), fifo(f), @@ -62,7 +62,6 @@ DataProcessor::DataProcessor(int ind, detectorType dtype, Fifo* f, rawDataModifyReadyCallBack(nullptr), pRawDataReady(nullptr) { - ThreadObject::CreateThread(); FILE_LOG(logDEBUG) << "DataProcessor " << ind << " created"; memset((void*)&timerBegin, 0, sizeof(timespec)); } @@ -71,13 +70,9 @@ DataProcessor::DataProcessor(int ind, detectorType dtype, Fifo* f, DataProcessor::~DataProcessor() { delete file; delete [] tempBuffer; - ThreadObject::DestroyThread(); } /** getters */ -std::string DataProcessor::GetType(){ - return TypeName; -} bool DataProcessor::IsRunning() { return runningFlag; @@ -155,20 +150,6 @@ void DataProcessor::SetGeneralData(GeneralData* g) { } -void DataProcessor::SetThreadPriority(int priority) { - struct sched_param param; - param.sched_priority = priority; - if (pthread_setschedparam(thread, SCHED_FIFO, ¶m) == EPERM) { - if (!index) { - FILE_LOG(logWARNING) << "Could not prioritize dataprocessing thread. " - "(No Root Privileges?)"; - } - } else { - FILE_LOG(logINFO) << "Priorities set - DataProcessor: " << priority; - } -} - - void DataProcessor::SetFileFormat(const fileFormat f) { if ((file != nullptr) && file->GetFileType() != f) { //remember the pointer values before they are destroyed diff --git a/slsReceiverSoftware/src/DataStreamer.cpp b/slsReceiverSoftware/src/DataStreamer.cpp index cd4a95302..b2f786472 100755 --- a/slsReceiverSoftware/src/DataStreamer.cpp +++ b/slsReceiverSoftware/src/DataStreamer.cpp @@ -18,7 +18,7 @@ const std::string DataStreamer::TypeName = "DataStreamer"; DataStreamer::DataStreamer(int ind, Fifo* f, uint32_t* dr, ROI* r, uint64_t* fi, int fd, std::string* ajh, int* nd, bool* gpEnable, bool* qe) : - ThreadObject(ind), + ThreadObject(ind, TypeName), runningFlag(0), generalData(nullptr), fifo(f), @@ -38,7 +38,6 @@ DataStreamer::DataStreamer(int ind, Fifo* f, uint32_t* dr, ROI* r, numDet[0] = nd[0]; numDet[1] = nd[1]; - ThreadObject::CreateThread(); FILE_LOG(logDEBUG) << "DataStreamer " << ind << " created"; } @@ -46,13 +45,9 @@ DataStreamer::DataStreamer(int ind, Fifo* f, uint32_t* dr, ROI* r, DataStreamer::~DataStreamer() { CloseZmqSocket(); delete [] completeBuffer; - ThreadObject::DestroyThread(); } /** getters */ -std::string DataStreamer::GetType(){ - return TypeName; -} bool DataStreamer::IsRunning() { return runningFlag; @@ -104,19 +99,6 @@ void DataStreamer::SetGeneralData(GeneralData* g) { generalData->Print(); } -void DataStreamer::SetThreadPriority(int priority) { - struct sched_param param; - param.sched_priority = priority; - if (pthread_setschedparam(thread, SCHED_FIFO, ¶m) == EPERM) { - if (!index) { - FILE_LOG(logWARNING) << "Could not prioritize datastreaming thread. " - "(No Root Privileges?)"; - } - } else { - FILE_LOG(logINFO) << "Priorities set - DataStreamer: " << priority; - } -} - void DataStreamer::SetNumberofDetectors(int* nd) { numDet[0] = nd[0]; numDet[1] = nd[1]; diff --git a/slsReceiverSoftware/src/HDF5File.cpp b/slsReceiverSoftware/src/HDF5File.cpp index 2fd45038b..20f5a87e0 100755 --- a/slsReceiverSoftware/src/HDF5File.cpp +++ b/slsReceiverSoftware/src/HDF5File.cpp @@ -13,7 +13,6 @@ #include -pthread_mutex_t HDF5File::Mutex = PTHREAD_MUTEX_INITIALIZER; H5File* HDF5File::masterfd = 0; hid_t HDF5File::virtualfd = 0; @@ -142,19 +141,14 @@ void HDF5File::CreateFile() { uint64_t framestosave = ((*maxFramesPerFile == 0) ? *numImages : // infinite images (((extNumImages - subFileIndex) > (*maxFramesPerFile)) ? // save up to maximum at a time (*maxFramesPerFile) : (extNumImages-subFileIndex))); - pthread_mutex_lock(&Mutex); - try{ - HDF5FileStatic::CreateDataFile(index, *overWriteEnable, currentFileName, (*numImages > 1), + + std::lock_guard lock(mutex); + HDF5FileStatic::CreateDataFile(index, *overWriteEnable, currentFileName, (*numImages > 1), subFileIndex, framestosave, nPixelsY, ((*dynamicRange==4) ? (nPixelsX/2) : nPixelsX), datatype, filefd, dataspace, dataset, HDF5_WRITER_VERSION, MAX_CHUNKED_IMAGES, dataspace_para, dataset_para, parameterNames, parameterDataTypes); - } catch(const RuntimeError &e) { - pthread_mutex_unlock(&Mutex); - throw; - } - pthread_mutex_unlock(&Mutex); if(!(*silentMode)) { FILE_LOG(logINFO) << *udpPortNumber << ": HDF5 File created: " << currentFileName; @@ -163,9 +157,10 @@ void HDF5File::CreateFile() { void HDF5File::CloseCurrentFile() { - pthread_mutex_lock(&Mutex); - HDF5FileStatic::CloseDataFile(index, filefd); - pthread_mutex_unlock(&Mutex); + { + std::lock_guard lock(mutex); + HDF5FileStatic::CloseDataFile(index, filefd); + } for (unsigned int i = 0; i < dataset_para.size(); ++i) delete dataset_para[i]; dataset_para.clear(); @@ -178,14 +173,14 @@ void HDF5File::CloseCurrentFile() { void HDF5File::CloseAllFiles() { numFilesinAcquisition = 0; - pthread_mutex_lock(&Mutex); - HDF5FileStatic::CloseDataFile(index, filefd); - if (master && (*detIndex==0)) { - HDF5FileStatic::CloseMasterDataFile(masterfd); - HDF5FileStatic::CloseVirtualDataFile(virtualfd); + { + std::lock_guard lock(mutex); + HDF5FileStatic::CloseDataFile(index, filefd); + if (master && (*detIndex==0)) { + HDF5FileStatic::CloseMasterDataFile(masterfd); + HDF5FileStatic::CloseVirtualDataFile(virtualfd); + } } - pthread_mutex_unlock(&Mutex); - for (unsigned int i = 0; i < dataset_para.size(); ++i) delete dataset_para[i]; dataset_para.clear(); @@ -206,9 +201,9 @@ void HDF5File::WriteToFile(char* buffer, int buffersize, uint64_t fnum, uint32_t } numFramesInFile++; numActualPacketsInFile += nump; - pthread_mutex_lock(&Mutex); - try { + std::lock_guard lock(mutex); + // extend dataset (when receiver start followed by many status starts (jungfrau))) if (fnum >= extNumImages) { HDF5FileStatic::ExtendDataset(index, dataspace, dataset, @@ -231,11 +226,6 @@ void HDF5File::WriteToFile(char* buffer, int buffersize, uint64_t fnum, uint32_t ((*maxFramesPerFile == 0) ? fnum : fnum%(*maxFramesPerFile)), dataset_para, (sls_receiver_header*) (buffer), parameterDataTypes); - } catch (const RuntimeError &e) { - pthread_mutex_unlock(&Mutex); - throw; - } - pthread_mutex_unlock(&Mutex); } @@ -253,15 +243,10 @@ void HDF5File::CreateMasterFile(bool mfwenable, masterAttributes& attr) { if(!(*silentMode)) { FILE_LOG(logINFO) << "Master File: " << masterFileName; } - pthread_mutex_lock(&Mutex); + std::lock_guard lock(mutex); attr.version = HDF5_WRITER_VERSION; - try{ - HDF5FileStatic::CreateMasterDataFile(masterfd, masterFileName, + HDF5FileStatic::CreateMasterDataFile(masterfd, masterFileName, *overWriteEnable, attr); - } catch (const RuntimeError &e) { - pthread_mutex_unlock(&Mutex); - throw; - } } } @@ -288,14 +273,13 @@ void HDF5File::EndofAcquisition(bool anyPacketsCaught, uint64_t numf) { // called only by the one maser receiver void HDF5File::CreateVirtualFile(uint64_t numf) { - pthread_mutex_lock(&Mutex); + std::lock_guard lock(mutex); std::string vname = HDF5FileStatic::CreateVirtualFileName(*filePath, *fileNamePrefix, *fileIndex); if(!(*silentMode)) { FILE_LOG(logINFO) << "Virtual File: " << vname; } - try { - HDF5FileStatic::CreateVirtualDataFile(vname, + HDF5FileStatic::CreateVirtualDataFile(vname, virtualfd, masterFileName, *filePath, *fileNamePrefix, *fileIndex, (*numImages > 1), *detIndex, *numUnitsPerDetector, @@ -306,11 +290,6 @@ void HDF5File::CreateVirtualFile(uint64_t numf) { numDetY, numDetX, nPixelsY, ((*dynamicRange==4) ? (nPixelsX/2) : nPixelsX), HDF5_WRITER_VERSION, parameterNames, parameterDataTypes); - } catch (const RuntimeError &e) { - pthread_mutex_unlock(&Mutex); - throw; - } - pthread_mutex_unlock(&Mutex); } // called only by the one maser receiver @@ -321,13 +300,7 @@ void HDF5File::LinkVirtualFileinMasterFile() { if ((*numImages > 1)) osfn << "_f" << std::setfill('0') << std::setw(12) << 0; std::string dsetname = osfn.str(); - pthread_mutex_lock(&Mutex); - try { - HDF5FileStatic::LinkVirtualInMaster(masterFileName, currentFileName, + std::lock_guard lock(mutex); + HDF5FileStatic::LinkVirtualInMaster(masterFileName, currentFileName, dsetname, parameterNames); - } catch (const RuntimeError &e) { - pthread_mutex_unlock(&Mutex); - throw; - } - pthread_mutex_unlock(&Mutex); } diff --git a/slsReceiverSoftware/src/Listener.cpp b/slsReceiverSoftware/src/Listener.cpp index 88957077c..2347f3da1 100755 --- a/slsReceiverSoftware/src/Listener.cpp +++ b/slsReceiverSoftware/src/Listener.cpp @@ -24,7 +24,7 @@ Listener::Listener(int ind, detectorType dtype, Fifo* f, std::atomic* uint32_t* portno, std::string* e, uint64_t* nf, uint32_t* dr, int64_t* us, int64_t* as, uint32_t* fpf, frameDiscardPolicy* fdp, bool* act, bool* depaden, bool* sm) : - ThreadObject(ind), + ThreadObject(ind, TypeName), runningFlag(0), generalData(nullptr), fifo(f), @@ -55,7 +55,6 @@ Listener::Listener(int ind, detectorType dtype, Fifo* f, std::atomic* numFramesStatistic(0), oddStartingPacket(true) { - ThreadObject::CreateThread(); FILE_LOG(logDEBUG) << "Listener " << ind << " created"; } @@ -65,15 +64,9 @@ Listener::~Listener() { sem_post(&semaphore_socket); sem_destroy(&semaphore_socket); } - - ThreadObject::DestroyThread(); } /** getters */ -std::string Listener::GetType(){ - return TypeName; -} - bool Listener::IsRunning() { return runningFlag; } @@ -153,19 +146,6 @@ void Listener::SetGeneralData(GeneralData* g) { } -void Listener::SetThreadPriority(int priority) { - struct sched_param param; - param.sched_priority = priority; - if (pthread_setschedparam(thread, SCHED_FIFO, ¶m) == EPERM) { - if (!index) { - FILE_LOG(logWARNING) << "Could not prioritize listener thread. " - "(No Root Privileges?)"; - } - } else { - FILE_LOG(logINFO) << "Priorities set - Listener: " << priority; - } -} - void Listener::CreateUDPSockets() { if (!(*activated)) { diff --git a/slsReceiverSoftware/src/ThreadObject.cpp b/slsReceiverSoftware/src/ThreadObject.cpp index 69e8dfca7..c4c426152 100755 --- a/slsReceiverSoftware/src/ThreadObject.cpp +++ b/slsReceiverSoftware/src/ThreadObject.cpp @@ -6,99 +6,71 @@ #include "ThreadObject.h" +#include "container_utils.h" #include #include -ThreadObject::ThreadObject(int ind): - index(ind), - alive(false), - killThread(false), - thread(0) -{ - PrintMembers(); +ThreadObject::ThreadObject(int threadIndex, std::string threadType) + : index(threadIndex), type(threadType) { + FILE_LOG(logDEBUG) << type << " thread created: " << index; + + sem_init(&semaphore,1,0); + + try { + threadObject = sls::make_unique(&ThreadObject::RunningThread, this); + } catch (...) { + throw sls::RuntimeError("Could not create " + type + " thread with index " + std::to_string(index)); + } } ThreadObject::~ThreadObject() { - DestroyThread(); -} + killThread = true; + sem_post(&semaphore); + threadObject->join(); -void ThreadObject::PrintMembers() { - FILE_LOG(logDEBUG) << "Index : " << index - << "\nalive: " << alive - << "\nkillThread: " << killThread - << "\npthread: " << thread; -} - - -void ThreadObject::DestroyThread() { - if(alive){ - killThread = true; - sem_post(&semaphore); - pthread_join(thread,nullptr); - sem_destroy(&semaphore); - killThread = false; - alive = false; - FILE_LOG(logDEBUG) << GetType() << " thread with index " << index << " destroyed successfully."; - } -} - - -void ThreadObject::CreateThread() { - if (alive) { - throw sls::RuntimeError("Cannot create " + GetType() + " thread " + std::to_string(index) + ". Already alive"); - } - sem_init(&semaphore,1,0); - killThread = false; - - if (pthread_create(&thread, nullptr,StartThread, (void*) this)){ - throw sls::RuntimeError("Could not create " + GetType() + " thread with index " + std::to_string(index)); - } - alive = true; - FILE_LOG(logDEBUG) << GetType() << " thread " << index << " created successfully."; -} - - -void* ThreadObject::StartThread(void* thisPointer) { - ((ThreadObject*)thisPointer)->RunningThread(); - return thisPointer; + sem_destroy(&semaphore); } void ThreadObject::RunningThread() { - FILE_LOG(logINFOBLUE) << "Created [ " << GetType() << "Thread " << index << ", " - "Tid: " << syscall(SYS_gettid) << "]"; + FILE_LOG(logINFOBLUE) << "Created [ " << type << "Thread " << index << ", Tid: " << syscall(SYS_gettid) << "]"; + FILE_LOG(logDEBUG) << type << " thread " << index << " created successfully."; + while(true) { - while(IsRunning()) { - ThreadExecution(); - - }//end of inner loop - - + } //wait till the next acquisition sem_wait(&semaphore); - if(killThread) { - FILE_LOG(logINFOBLUE) << "Exiting [ " << GetType() << - " Thread " << index << ", Tid: " << syscall(SYS_gettid) << "]"; - pthread_exit(nullptr); + break; } - - }//end of outer loop + } + + FILE_LOG(logDEBUG) << type << " thread with index " << index << " destroyed successfully."; + FILE_LOG(logINFOBLUE) << "Exiting [ " << type << " Thread " << index << ", Tid: " << syscall(SYS_gettid) << "]"; } - - void ThreadObject::Continue() { sem_post(&semaphore); } - +void ThreadObject::SetThreadPriority(int priority) { + struct sched_param param; + param.sched_priority = priority; + if (pthread_setschedparam(threadObject->native_handle(), SCHED_FIFO, ¶m) == EPERM) { + if (!index) { + FILE_LOG(logWARNING) << "Could not prioritize " << type << " thread. " + "(No Root Privileges?)"; + } + } else { + FILE_LOG(logINFO) << "Priorities set - " << type << ": " << priority; + } +}