introspection major optimization
This commit is contained in:
@@ -17,13 +17,49 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "piintrospection_containers.h"
|
||||||
|
|
||||||
|
PIIntrospectionContainersType::~PIIntrospectionContainersType() {
|
||||||
|
if (has_demangled) {
|
||||||
|
//free((void*)demangled);
|
||||||
|
has_demangled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
|
#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
|
||||||
|
|
||||||
#include "piintrospection_containers.h"
|
|
||||||
#include "piintrospection_containers_p.h"
|
#include "piintrospection_containers_p.h"
|
||||||
|
|
||||||
__PIINTROSPECTION_SINGLETON_CPP__(Containers)
|
__PIINTROSPECTION_SINGLETON_CPP__(Containers)
|
||||||
|
|
||||||
|
#ifdef CC_GCC
|
||||||
|
# include <cxxabi.h>
|
||||||
|
const char * demangle(const char * name) {
|
||||||
|
int status = -4;
|
||||||
|
char * res = abi::__cxa_demangle(name, NULL, NULL, &status);
|
||||||
|
if (status == 0) return res;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
const char * demangle(const char * name) {return name;}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void PIIntrospectionContainersType::finish() {
|
||||||
|
inited = true;
|
||||||
|
if (!name) {
|
||||||
|
printf("[PIIntrospectionContainersType::finish] Null name!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t l = strlen(name);
|
||||||
|
if (l > 0)
|
||||||
|
id = piHashData((const uchar*)name, int(l));
|
||||||
|
demangled = demangle(name);
|
||||||
|
has_demangled = name != demangled;
|
||||||
|
//printf("create typeinfo for %s -> %s\n", name, demangled);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PIIntrospectionContainersInterface::PIIntrospectionContainersInterface() {
|
PIIntrospectionContainersInterface::PIIntrospectionContainersInterface() {
|
||||||
p = new PIIntrospectionContainers();
|
p = new PIIntrospectionContainers();
|
||||||
@@ -35,33 +71,33 @@ PIIntrospectionContainersInterface::~PIIntrospectionContainersInterface() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIntrospectionContainersInterface::containerNew(const char * tn, uint isz) {
|
void PIIntrospectionContainersInterface::containerNew(const PIIntrospectionContainersType & ti, uint isz) {
|
||||||
p->containerNew(tn, isz);
|
p->containerNew(ti, isz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIntrospectionContainersInterface::containerDelete(const char * tn) {
|
void PIIntrospectionContainersInterface::containerDelete(const PIIntrospectionContainersType & ti) {
|
||||||
p->containerDelete(tn);
|
p->containerDelete(ti);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIntrospectionContainersInterface::containerAlloc(const char * tn, ullong cnt) {
|
void PIIntrospectionContainersInterface::containerAlloc(const PIIntrospectionContainersType & ti, ullong cnt) {
|
||||||
p->containerAlloc(tn, cnt);
|
p->containerAlloc(ti, cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIntrospectionContainersInterface::containerFree(const char * tn, ullong cnt) {
|
void PIIntrospectionContainersInterface::containerFree(const PIIntrospectionContainersType & ti, ullong cnt) {
|
||||||
p->containerFree(tn, cnt);
|
p->containerFree(ti, cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIntrospectionContainersInterface::containerUsed(const char * tn, ullong cnt) {
|
void PIIntrospectionContainersInterface::containerUsed(const PIIntrospectionContainersType & ti, ullong cnt) {
|
||||||
p->containerUsed(tn, cnt);
|
p->containerUsed(ti, cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIntrospectionContainersInterface::containerUnused(const char * tn, ullong cnt) {
|
void PIIntrospectionContainersInterface::containerUnused(const PIIntrospectionContainersType & ti, ullong cnt) {
|
||||||
p->containerUnused(tn, cnt);
|
p->containerUnused(ti, cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -20,27 +20,48 @@
|
|||||||
#ifndef PIINTROSPECTION_CONTAINERS_H
|
#ifndef PIINTROSPECTION_CONTAINERS_H
|
||||||
#define PIINTROSPECTION_CONTAINERS_H
|
#define PIINTROSPECTION_CONTAINERS_H
|
||||||
|
|
||||||
|
#include "pibase.h"
|
||||||
|
|
||||||
|
struct PIP_EXPORT PIIntrospectionContainersType {
|
||||||
|
~PIIntrospectionContainersType();
|
||||||
|
void finish();
|
||||||
|
uint id = 0;
|
||||||
|
const char * name = nullptr;
|
||||||
|
const char * demangled = "?";
|
||||||
|
bool inited = false;
|
||||||
|
bool has_demangled = false;
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
|
#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
|
||||||
|
|
||||||
#include "piintrospection_base.h"
|
#include "piintrospection_base.h"
|
||||||
|
|
||||||
class PIIntrospectionContainers;
|
class PIIntrospectionContainers;
|
||||||
|
|
||||||
#define PIINTROSPECTION_CONTAINERS (PIIntrospectionContainersInterface::instance())//(PIIntrospectionContainersInterface::instance())
|
template<typename T>
|
||||||
|
class PIIntrospectionContainersTypeInfo {
|
||||||
|
public:
|
||||||
|
static const PIIntrospectionContainersType & get() {
|
||||||
|
static PIIntrospectionContainersType ret = create();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static PIIntrospectionContainersType create() {
|
||||||
|
PIIntrospectionContainersType ret;
|
||||||
|
ret.name = __PIP_TYPENAME__(T);
|
||||||
|
ret.finish();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef CC_GCC
|
#define PIINTROSPECTION_CONTAINERS (PIIntrospectionContainersInterface::instance())
|
||||||
# include <typeinfo>
|
|
||||||
# define _PIIS_TYPENAME_(t) typeid(t).name()
|
|
||||||
#else
|
|
||||||
# define _PIIS_TYPENAME_(t) ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
# define PIINTROSPECTION_CONTAINER_NEW(t, isz) PIINTROSPECTION_CONTAINERS->containerNew (_PIIS_TYPENAME_(t), isz);
|
# define PIINTROSPECTION_CONTAINER_NEW(t, isz) PIINTROSPECTION_CONTAINERS->containerNew (PIIntrospectionContainersTypeInfo<t>::get(), isz);
|
||||||
# define PIINTROSPECTION_CONTAINER_DELETE(t) PIINTROSPECTION_CONTAINERS->containerDelete(_PIIS_TYPENAME_(t));
|
# define PIINTROSPECTION_CONTAINER_DELETE(t) PIINTROSPECTION_CONTAINERS->containerDelete(PIIntrospectionContainersTypeInfo<t>::get());
|
||||||
# define PIINTROSPECTION_CONTAINER_ALLOC(t, cnt) PIINTROSPECTION_CONTAINERS->containerAlloc (_PIIS_TYPENAME_(t), cnt);
|
# define PIINTROSPECTION_CONTAINER_ALLOC(t, cnt) PIINTROSPECTION_CONTAINERS->containerAlloc (PIIntrospectionContainersTypeInfo<t>::get(), cnt);
|
||||||
# define PIINTROSPECTION_CONTAINER_FREE(t, cnt) PIINTROSPECTION_CONTAINERS->containerFree (_PIIS_TYPENAME_(t), cnt);
|
# define PIINTROSPECTION_CONTAINER_FREE(t, cnt) PIINTROSPECTION_CONTAINERS->containerFree (PIIntrospectionContainersTypeInfo<t>::get(), cnt);
|
||||||
# define PIINTROSPECTION_CONTAINER_USED(t, cnt) PIINTROSPECTION_CONTAINERS->containerUsed (_PIIS_TYPENAME_(t), cnt);
|
# define PIINTROSPECTION_CONTAINER_USED(t, cnt) PIINTROSPECTION_CONTAINERS->containerUsed (PIIntrospectionContainersTypeInfo<t>::get(), cnt);
|
||||||
# define PIINTROSPECTION_CONTAINER_UNUSED(t, cnt) PIINTROSPECTION_CONTAINERS->containerUnused(_PIIS_TYPENAME_(t), cnt);
|
# define PIINTROSPECTION_CONTAINER_UNUSED(t, cnt) PIINTROSPECTION_CONTAINERS->containerUnused(PIIntrospectionContainersTypeInfo<t>::get(), cnt);
|
||||||
|
|
||||||
|
|
||||||
class PIP_EXPORT PIIntrospectionContainersInterface {
|
class PIP_EXPORT PIIntrospectionContainersInterface {
|
||||||
@@ -49,12 +70,12 @@ class PIP_EXPORT PIIntrospectionContainersInterface {
|
|||||||
public:
|
public:
|
||||||
__PIINTROSPECTION_SINGLETON_H__(Containers)
|
__PIINTROSPECTION_SINGLETON_H__(Containers)
|
||||||
|
|
||||||
void containerNew (const char * tn, uint isz);
|
void containerNew (const PIIntrospectionContainersType & ti, uint isz);
|
||||||
void containerDelete(const char * tn);
|
void containerDelete(const PIIntrospectionContainersType & ti);
|
||||||
void containerAlloc (const char * tn, ullong cnt);
|
void containerAlloc (const PIIntrospectionContainersType & ti, ullong cnt);
|
||||||
void containerFree (const char * tn, ullong cnt);
|
void containerFree (const PIIntrospectionContainersType & ti, ullong cnt);
|
||||||
void containerUsed (const char * tn, ullong cnt);
|
void containerUsed (const PIIntrospectionContainersType & ti, ullong cnt);
|
||||||
void containerUnused(const char * tn, ullong cnt);
|
void containerUnused(const PIIntrospectionContainersType & ti, ullong cnt);
|
||||||
|
|
||||||
PIIntrospectionContainers * p;
|
PIIntrospectionContainers * p;
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -18,38 +18,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "piintrospection_containers_p.h"
|
#include "piintrospection_containers_p.h"
|
||||||
|
#include "piintrospection_containers.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#ifdef CC_GCC
|
|
||||||
# include <cxxabi.h>
|
|
||||||
const PIString demangle(const char * name) {
|
|
||||||
int status = -4;
|
|
||||||
char * res = abi::__cxa_demangle(name, NULL, NULL, &status);
|
|
||||||
PIString ret((status == 0) ? res : name);
|
|
||||||
free(res);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
const PIString demangle(const char * name) {return PIString(name);}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PIIntrospectionContainers::PIIntrospectionContainers() {
|
PIIntrospectionContainers::PIIntrospectionContainers() {
|
||||||
//printf("PIIntrospectionContainers %p\n", this);
|
//printf("PIIntrospectionContainers %p\n", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIntrospectionContainers::containerNew(const char * tn, uint isz) {
|
void PIIntrospectionContainers::containerNew(const PIIntrospectionContainersType & ti, uint isz) {
|
||||||
uint id = typeID(tn);
|
PISpinlockLocker _ml(mutex);
|
||||||
PIMutexLocker _ml(mutex);
|
|
||||||
//printf("containerNew lock\n");
|
//printf("containerNew lock\n");
|
||||||
std::string & n(typenames[id]);
|
PIIntrospectionContainersType & t(types[ti.id]);
|
||||||
_Type & d(data[id]);
|
_Type & d(data[ti.id]);
|
||||||
if (n.empty()) {
|
if (!t.inited) {
|
||||||
n = tn;
|
t = ti;
|
||||||
d.id = id;
|
d.id = ti.id;
|
||||||
d.item_size = isz;
|
d.item_size = isz;
|
||||||
}
|
}
|
||||||
d.count++;
|
d.count++;
|
||||||
@@ -57,49 +42,41 @@ void PIIntrospectionContainers::containerNew(const char * tn, uint isz) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIntrospectionContainers::containerDelete(const char * tn) {
|
void PIIntrospectionContainers::containerDelete(const PIIntrospectionContainersType & ti) {
|
||||||
PIMutexLocker _ml(mutex);
|
PISpinlockLocker _ml(mutex);
|
||||||
data[typeID(tn)].count--;
|
data[ti.id].count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIntrospectionContainers::containerAlloc(const char * tn, ullong cnt) {
|
void PIIntrospectionContainers::containerAlloc(const PIIntrospectionContainersType & ti, ullong cnt) {
|
||||||
//printf(" alloc %s %d\n", tn, cnt);
|
//printf(" alloc %s %d\n", tn, cnt);
|
||||||
if (cnt == 0) return;
|
if (cnt == 0) return;
|
||||||
PIMutexLocker _ml(mutex);
|
PISpinlockLocker _ml(mutex);
|
||||||
data[typeID(tn)].allocated += cnt;
|
data[ti.id].allocated += cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIntrospectionContainers::containerFree(const char * tn, ullong cnt) {
|
void PIIntrospectionContainers::containerFree(const PIIntrospectionContainersType & ti, ullong cnt) {
|
||||||
//printf(" free %s %d\n", tn, cnt);
|
//printf(" free %s %d\n", tn, cnt);
|
||||||
if (cnt == 0) return;
|
if (cnt == 0) return;
|
||||||
PIMutexLocker _ml(mutex);
|
PISpinlockLocker _ml(mutex);
|
||||||
data[typeID(tn)].allocated -= cnt;
|
data[ti.id].allocated -= cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIntrospectionContainers::containerUsed(const char * tn, ullong cnt) {
|
void PIIntrospectionContainers::containerUsed(const PIIntrospectionContainersType & ti, ullong cnt) {
|
||||||
//printf(" used %s %d\n", tn, cnt);
|
//printf(" used %s %d\n", tn, cnt);
|
||||||
if (cnt == 0) return;
|
if (cnt == 0) return;
|
||||||
PIMutexLocker _ml(mutex);
|
PISpinlockLocker _ml(mutex);
|
||||||
data[typeID(tn)].used += cnt;
|
data[ti.id].used += cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIIntrospectionContainers::containerUnused(const char * tn, ullong cnt) {
|
void PIIntrospectionContainers::containerUnused(const PIIntrospectionContainersType & ti, ullong cnt) {
|
||||||
//printf("unused %s %d\n", tn, cnt);
|
//printf("unused %s %d\n", tn, cnt);
|
||||||
if (cnt == 0) return;
|
if (cnt == 0) return;
|
||||||
PIMutexLocker _ml(mutex);
|
PISpinlockLocker _ml(mutex);
|
||||||
data[typeID(tn)].used -= cnt;
|
data[ti.id].used -= cnt;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint PIIntrospectionContainers::typeID(const char * tn) {
|
|
||||||
if (!tn) return 0u;
|
|
||||||
size_t l = strlen(tn);
|
|
||||||
if (l == 0) return 0u;
|
|
||||||
return piHashData((const uchar*)tn, int(l));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -107,15 +84,15 @@ PIVector<PIIntrospectionContainers::TypeInfo> PIIntrospectionContainers::getInfo
|
|||||||
PIVector<PIIntrospectionContainers::TypeInfo> ret;
|
PIVector<PIIntrospectionContainers::TypeInfo> ret;
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
std::map<uint, PIIntrospectionContainers::_Type> d = data;
|
std::map<uint, PIIntrospectionContainers::_Type> d = data;
|
||||||
std::map<uint, std::string> t = typenames;
|
std::map<uint, PIIntrospectionContainersType> t = types;
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
ret.reserve(t.size());
|
ret.reserve(t.size());
|
||||||
for (typename std::map<uint, std::string>::const_iterator i = t.begin(); i != t.end(); ++i) {
|
for (typename std::map<uint, PIIntrospectionContainersType>::const_iterator i = t.begin(); i != t.end(); ++i) {
|
||||||
ret.push_back(TypeInfo());
|
ret.push_back(TypeInfo());
|
||||||
TypeInfo & ti(ret.back());
|
TypeInfo & ti(ret.back());
|
||||||
_Type & _t(d[i->first]);
|
_Type & _t(d[i->first]);
|
||||||
memcpy((void*)&ti, (const void*)&_t, sizeof(_t));
|
memcpy((void*)&ti, (const void*)&_t, sizeof(_t));
|
||||||
ti.name = demangle(i->second.c_str());
|
ti.name = PIStringAscii(i->second.demangled);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#ifndef PIINTROSPECTION_CONTAINERS_P_H
|
#ifndef PIINTROSPECTION_CONTAINERS_P_H
|
||||||
#define PIINTROSPECTION_CONTAINERS_P_H
|
#define PIINTROSPECTION_CONTAINERS_P_H
|
||||||
|
|
||||||
#include "pimutex.h"
|
#include "pispinlock.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "picrc.h"
|
#include "picrc.h"
|
||||||
@@ -32,14 +32,12 @@ public:
|
|||||||
|
|
||||||
struct TypeInfo;
|
struct TypeInfo;
|
||||||
|
|
||||||
void containerNew (const char * tn, uint isz);
|
void containerNew (const PIIntrospectionContainersType & ti, uint isz);
|
||||||
void containerDelete(const char * tn);
|
void containerDelete(const PIIntrospectionContainersType & ti);
|
||||||
void containerAlloc (const char * tn, ullong cnt);
|
void containerAlloc (const PIIntrospectionContainersType & ti, ullong cnt);
|
||||||
void containerFree (const char * tn, ullong cnt);
|
void containerFree (const PIIntrospectionContainersType & ti, ullong cnt);
|
||||||
void containerUsed (const char * tn, ullong cnt);
|
void containerUsed (const PIIntrospectionContainersType & ti, ullong cnt);
|
||||||
void containerUnused(const char * tn, ullong cnt);
|
void containerUnused(const PIIntrospectionContainersType & ti, ullong cnt);
|
||||||
|
|
||||||
uint typeID(const char * tn);
|
|
||||||
|
|
||||||
PIVector<TypeInfo> getInfo() const;
|
PIVector<TypeInfo> getInfo() const;
|
||||||
|
|
||||||
@@ -63,8 +61,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::map<uint, _Type> data;
|
std::map<uint, _Type> data;
|
||||||
std::map<uint, std::string> typenames;
|
std::map<uint, PIIntrospectionContainersType> types;
|
||||||
mutable PIMutex mutex;
|
mutable PISpinlock mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PIIntrospectionContainers::TypeInfo & v);
|
PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PIIntrospectionContainers::TypeInfo & v);
|
||||||
|
|||||||
@@ -20,7 +20,16 @@
|
|||||||
#ifndef PIINTROSPECTION_SERVER_H
|
#ifndef PIINTROSPECTION_SERVER_H
|
||||||
#define PIINTROSPECTION_SERVER_H
|
#define PIINTROSPECTION_SERVER_H
|
||||||
|
|
||||||
#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
|
#ifdef DOXYGEN
|
||||||
|
|
||||||
|
//! \~\ingroup Introspection
|
||||||
|
//! \~english Start introspection server with name "name"
|
||||||
|
//! \~russian Запускает сервер интроспекции с именем "name"
|
||||||
|
# define PIINTROSPECTION_START(name)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
# if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
|
||||||
|
|
||||||
#include "pipeer.h"
|
#include "pipeer.h"
|
||||||
|
|
||||||
@@ -53,8 +62,10 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
# else
|
||||||
# define PIINTROSPECTION_START(name)
|
# define PIINTROSPECTION_START(name)
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
|
#endif // DOXYGEN
|
||||||
|
|
||||||
#endif // PIINTROSPECTION_SERVER_H
|
#endif // PIINTROSPECTION_SERVER_H
|
||||||
|
|||||||
@@ -144,9 +144,8 @@ PIResourcesStorage * PIResourcesStorage::instance() {
|
|||||||
|
|
||||||
PIByteArray & operator <<(PIByteArray & b, const PIResourcesStorage::__RCEntry & v) {
|
PIByteArray & operator <<(PIByteArray & b, const PIResourcesStorage::__RCEntry & v) {
|
||||||
PIChunkStream cs;
|
PIChunkStream cs;
|
||||||
cs << cs.chunk(1, v.section) << cs.chunk(2, v.name) << cs.chunk(3, v.file)
|
cs.add(1, v.section).add(2, v.name).add(3, v.file).add(4, v.size)
|
||||||
<< cs.chunk(4, v.size) << cs.chunk(5, v.offset) << cs.chunk(6, v.flags)
|
.add(5, v.offset).add(6, v.flags).add(7, v.alias);
|
||||||
<< cs.chunk(7, v.alias);
|
|
||||||
b << cs.data();
|
b << cs.data();
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
//! \defgroup Thread
|
//! \defgroup Thread
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Multithreading support.
|
//! \~english Multithreading support
|
||||||
//! \~russian Поддержка многопоточности.
|
//! \~russian Поддержка многопоточности
|
||||||
//!
|
//!
|
||||||
//! \~\details
|
//! \~\details
|
||||||
//! \~english \section cmake_module Building with CMake
|
//! \~english \section cmake_module Building with CMake
|
||||||
|
|||||||
Reference in New Issue
Block a user