2019年9月

两个版本的链接:

https://github.com/neosmart/pevents

https://github.com/moya-lang/Event

 

第一个版本能够模拟等待多个事件中的一个触发,而后者仅最多支持一个事件

但第一个版本在UnlockedWaitForEvent执行后,是需要增加一个判断的,否则会不正确

代码:

#if 0

//#define PULSE//#define WFMO
#include<assert.h>#include<errno.h>#include<pthread.h>#include<sys/time.h>#ifdef WFMO
#include
<algorithm>#include<deque> #endif structSyncObjectPosix_event_st;//Function declarations void* CreateEvent(void* lpEventAttributes = nullptr, bool manualReset = false, bool initialState = false, void* lpName =nullptr);int DestroyEvent(void* event);//int WaitForEvent(void* event, uint64_t milliseconds = -1); int WaitForSingleObject(void* event, uint64_t milliseconds = -1);int SetEvent(void* event);int ResetEvent(void* event);
#ifdef WFMO
int WaitForMultipleObjects(int nCount,const void* *lpHandles, boolbWaitAll, uint64_t milliseconds);int WaitForMultipleEvents(void* *events, int count, boolwaitAll,
uint64_t milliseconds);
int WaitForMultipleEvents(void* *events, int count, boolwaitAll,
uint64_t milliseconds,
int &index);#endif#ifdef PULSEint PulseEvent(void* event);#endif#ifdef WFMO//Each call to WaitForMultipleObjects initializes a neosmart_wfmo_t object which tracks//the progress of the caller's multi-object wait and dispatches responses accordingly.//One neosmart_wfmo_t struct is shared for all events in a single WFMO call typedef structSyncObjectPosix_wfmo_st {
pthread_mutex_t Mutex;
pthread_cond_t CVariable;
intRefCount;
union {
int FiredEvent; //WFSO int EventsLeft; //WFMO } Status;boolWaitAll;boolStillWaiting;voidDestroy() {
pthread_mutex_destroy(
&Mutex);
pthread_cond_destroy(
&CVariable);
}
}SyncObjectPosix_wfmo_st;
//typedef SyncObjectPosix_wfmo_t_ *SyncObjectPosix_wfmo_t;//A neosmart_wfmo_info_t object is registered with each event waited on in a WFMO//This reference to neosmart_wfmo_t_ is how the event knows whom to notify when triggered typedef structSyncObjectPosix_wfmo_info_st {
SyncObjectPosix_wfmo_st
*Waiter;intWaitIndex;
}SyncObjectPosix_wfmo_info_st;
//typedef SyncObjectPosix_wfmo_info_t_ *nSyncObjectPosix_wfmo_info_t; #endif //WFMO //The basic event structure, passed to the caller as an opaque pointer when creating events typedef structSyncObjectPosix_event_st {
pthread_cond_t CVariable;
pthread_mutex_t Mutex;
boolAutoReset;boolState;
#ifdef WFMO
std::deque
<SyncObjectPosix_wfmo_info_st>RegisteredWaits;#endif}SyncObjectPosix_event_st;

#ifdef WFMO
boolRemoveExpiredWaitHelper(SyncObjectPosix_wfmo_info_st wait) {int result = pthread_mutex_trylock(&wait.Waiter->Mutex);if (result ==EBUSY) {return false;
}

assert(result
== 0);if (wait.Waiter->StillWaiting == false) {--wait.Waiter->RefCount;
assert(wait.Waiter
->RefCount >= 0);bool destroy = wait.Waiter->RefCount == 0;
result
= pthread_mutex_unlock(&wait.Waiter->Mutex);
assert(result
== 0);if(destroy) {
wait.Waiter
->Destroy();deletewait.Waiter;
}
return true;
}

result
= pthread_mutex_unlock(&wait.Waiter->Mutex);
assert(result
== 0);return false;
}
#endif //WFMO void* CreateEvent(void* lpEventAttributes, bool manualReset, bool initialState, void*lpName) {
SyncObjectPosix_event_st
* event = newSyncObjectPosix_event_st;int result = pthread_cond_init(&event->CVariable, 0);
assert(result
== 0);

result
= pthread_mutex_init(&event->Mutex, 0);
assert(result
== 0);event->State = false;event->AutoReset = !manualReset;if(initialState) {
result
= SetEvent(event);
assert(result
== 0);
}
return event;
}
int UnlockedWaitForEvent(void* event, uint64_t milliseconds) {int result = 0;if (!((SyncObjectPosix_event_st*)event)->State) {//Zero-timeout event state check optimization if (milliseconds == 0) {returnWAIT_TIMEOUT;
}

timespec ts;
if (milliseconds != (uint64_t)-1) {
timeval tv;
gettimeofday(
&tv, NULL);

uint64_t nanoseconds
= ((uint64_t)tv.tv_sec) * 1000 * 1000 * 1000 +milliseconds* 1000 * 1000 + ((uint64_t)tv.tv_usec) * 1000;

ts.tv_sec
= nanoseconds / 1000 / 1000 / 1000;
ts.tv_nsec
= (nanoseconds - ((uint64_t)ts.tv_sec) * 1000 * 1000 * 1000);
}
do{//Regardless of whether it's an auto-reset or manual-reset event://wait to obtain the event, then lock anyone else out if (milliseconds != (uint64_t)-1) {
result
= pthread_cond_timedwait(&((SyncObjectPosix_event_st*)event)->CVariable, &((SyncObjectPosix_event_st*)event)->Mutex, &ts);
}
else{
result
= pthread_cond_wait(&((SyncObjectPosix_event_st*)event)->CVariable, &((SyncObjectPosix_event_st*)event)->Mutex);
}
}
while (result == 0 && !((SyncObjectPosix_event_st*)event)->State);if (result == 0 && ((SyncObjectPosix_event_st*)event)->AutoReset) {//We've only accquired the event if the wait succeeded ((SyncObjectPosix_event_st*)event)->State = false;
}
}
else if (((SyncObjectPosix_event_st*)event)->AutoReset) {//It's an auto-reset event that's currently available;//we need to stop anyone else from using it result = 0;
((SyncObjectPosix_event_st
*)event)->State = false;
}
//Else we're trying to obtain a manual reset event with a signaled state;//don't do anything returnresult;
}
int WaitForSingleObject(void* event, uint64_t milliseconds) {inttempResult;if (milliseconds == 0) {
tempResult
= pthread_mutex_trylock(&((SyncObjectPosix_event_st*)event)->Mutex);if (tempResult ==EBUSY) {returnWAIT_TIMEOUT;
}
}
else{
tempResult
= pthread_mutex_lock(&((SyncObjectPosix_event_st*)event)->Mutex);
}

assert(tempResult
== 0);int result = UnlockedWaitForEvent(((SyncObjectPosix_event_st*)event), milliseconds);

tempResult
= pthread_mutex_unlock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(tempResult
== 0);if (result ==ETIMEDOUT) {returnWAIT_TIMEOUT;
}
returnresult;
}

#ifdef WFMO
int WaitForMultipleEvents(void* *events, int count, boolwaitAll,
uint64_t milliseconds) {
intunused;returnWaitForMultipleEvents(events, count, waitAll, milliseconds, unused);
}
int WaitForMultipleEvents(void* *events, int count, boolwaitAll,
uint64_t milliseconds,
int &waitIndex) {
SyncObjectPosix_wfmo_st
* wfmo = newSyncObjectPosix_wfmo_st;

SyncObjectPosix_event_st
** pp_events = (SyncObjectPosix_event_st**)events;int result = 0;int tempResult = pthread_mutex_init(&wfmo->Mutex, 0);
assert(tempResult
== 0);

tempResult
= pthread_cond_init(&wfmo->CVariable, 0);
assert(tempResult
== 0);

SyncObjectPosix_wfmo_info_st waitInfo;
waitInfo.Waiter
=wfmo;
waitInfo.WaitIndex
= -1;

wfmo
->WaitAll =waitAll;
wfmo
->StillWaiting = true;
wfmo
->RefCount = 1;if(waitAll) {
wfmo
->Status.EventsLeft =count;
}
else{
wfmo
->Status.FiredEvent = -1;
}

tempResult
= pthread_mutex_lock(&wfmo->Mutex);
assert(tempResult
== 0);bool done = false;
waitIndex
= -1;for (int i = 0; i < count; ++i) {
waitInfo.WaitIndex
=i;//Must not release lock until RegisteredWait is potentially added tempResult = pthread_mutex_lock(&pp_events[i]->Mutex);
assert(tempResult
== 0);//Before adding this wait to the list of registered waits, let's clean up old, expired//waits while we have the event lock anyway pp_events[i]->RegisteredWaits.erase(std::remove_if(pp_events[i]->RegisteredWaits.begin(),
pp_events[i]
->RegisteredWaits.end(),
RemoveExpiredWaitHelper),
pp_events[i]
->RegisteredWaits.end());if (UnlockedWaitForEvent(events[i], 0) == 0) {
tempResult
= pthread_mutex_unlock(&pp_events[i]->Mutex);
assert(tempResult
== 0);if(waitAll) {--wfmo->Status.EventsLeft;
assert(wfmo
->Status.EventsLeft >= 0);
}
else{
wfmo
->Status.FiredEvent =i;
waitIndex
=i;
done
= true;break;
}
}
else{
pp_events[i]
->RegisteredWaits.push_back(waitInfo);++wfmo->RefCount;

tempResult
= pthread_mutex_unlock(&pp_events[i]->Mutex);
assert(tempResult
== 0);
}
}
//We set the `done` flag above in case of WaitAny and at least one event was set.//But we need to check again here if we were doing a WaitAll or else we'll incorrectly//return WAIT_TIMEOUT. if (waitAll && wfmo->Status.EventsLeft == 0) {
done
= true;
}

timespec ts;
if (!done) {if (milliseconds == 0) {
result
=WAIT_TIMEOUT;
done
= true;
}
else if (milliseconds != (uint64_t)-1) {
timeval tv;
gettimeofday(
&tv, NULL);

uint64_t nanoseconds
= ((uint64_t)tv.tv_sec) * 1000 * 1000 * 1000 +milliseconds* 1000 * 1000 + ((uint64_t)tv.tv_usec) * 1000;

ts.tv_sec
= nanoseconds / 1000 / 1000 / 1000;
ts.tv_nsec
= (nanoseconds - ((uint64_t)ts.tv_sec) * 1000 * 1000 * 1000);
}
}
while (!done) {//One (or more) of the events we're monitoring has been triggered?//If we're waiting for all events, assume we're done and check if there's an event that//hasn't fired But if we're waiting for just one event, assume we're not done until we//find a fired event done = (waitAll && wfmo->Status.EventsLeft == 0) ||(!waitAll && wfmo->Status.FiredEvent != -1);if (!done) {if (milliseconds != (uint64_t)-1) {
result
= pthread_cond_timedwait(&wfmo->CVariable, &wfmo->Mutex, &ts);
}
else{
result
= pthread_cond_wait(&wfmo->CVariable, &wfmo->Mutex);
}
if (result != 0) {break;
}
}
}

waitIndex
= wfmo->Status.FiredEvent;
wfmo
->StillWaiting = false;--wfmo->RefCount;
assert(wfmo
->RefCount >= 0);bool destroy = wfmo->RefCount == 0;
tempResult
= pthread_mutex_unlock(&wfmo->Mutex);
assert(tempResult
== 0);if(destroy) {
wfmo
->Destroy();deletewfmo;
}
returnresult;
}
#endif //WFMO int CloseHandle(void* event) {return DestroyEvent(event);
}
int DestroyEvent(void* event) {int result = 0;

#ifdef WFMO
result
= pthread_mutex_lock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result
== 0);
((SyncObjectPosix_event_st
*)event)->RegisteredWaits.erase(std::remove_if(((SyncObjectPosix_event_st*)event)->RegisteredWaits.begin(),
((SyncObjectPosix_event_st
*)event)->RegisteredWaits.end(),
RemoveExpiredWaitHelper),
((SyncObjectPosix_event_st
*)event)->RegisteredWaits.end());
result
= pthread_mutex_unlock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result
== 0);#endifresult= pthread_cond_destroy(&((SyncObjectPosix_event_st*)event)->CVariable);
assert(result
== 0);

result
= pthread_mutex_destroy(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result
== 0);delete ((SyncObjectPosix_event_st*)event);return 0;
}
int SetEvent(void* event) {int result = pthread_mutex_lock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result
== 0);

((SyncObjectPosix_event_st
*)event)->State = true;//Depending on the event type, we either trigger everyone or only one if (((SyncObjectPosix_event_st*)event)->AutoReset) {
#ifdef WFMO
while (!((SyncObjectPosix_event_st*)event)->RegisteredWaits.empty()) {
SyncObjectPosix_wfmo_info_st
* i = &((SyncObjectPosix_event_st*)event)->RegisteredWaits.front();

result
= pthread_mutex_lock(&i->Waiter->Mutex);
assert(result
== 0);--i->Waiter->RefCount;
assert(i
->Waiter->RefCount >= 0);if (!i->Waiter->StillWaiting) {bool destroy = i->Waiter->RefCount == 0;
result
= pthread_mutex_unlock(&i->Waiter->Mutex);
assert(result
== 0);if(destroy) {
i
->Waiter->Destroy();delete i->Waiter;
}
((SyncObjectPosix_event_st
*)event)->RegisteredWaits.pop_front();continue;
}

((SyncObjectPosix_event_st
*)event)->State = false;if (i->Waiter->WaitAll) {--i->Waiter->Status.EventsLeft;
assert(i
->Waiter->Status.EventsLeft >= 0);//We technically should do i->Waiter->StillWaiting = Waiter->Status.EventsLeft//!= 0 but the only time it'll be equal to zero is if we're the last event, so//no one else will be checking the StillWaiting flag. We're good to go without//it. } else{
i
->Waiter->Status.FiredEvent = i->WaitIndex;
i
->Waiter->StillWaiting = false;
}

result
= pthread_mutex_unlock(&i->Waiter->Mutex);
assert(result
== 0);

result
= pthread_cond_signal(&i->Waiter->CVariable);
assert(result
== 0);

((SyncObjectPosix_event_st
*)event)->RegisteredWaits.pop_front();

result
= pthread_mutex_unlock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result
== 0);return 0;
}
#endif //WFMO //event->State can be false if compiled with WFMO support if (((SyncObjectPosix_event_st*)event)->State) {
result
= pthread_mutex_unlock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result
== 0);

result
= pthread_cond_signal(&((SyncObjectPosix_event_st*)event)->CVariable);
assert(result
== 0);return 0;
}
}
else{
#ifdef WFMO
for (size_t i = 0; i < ((SyncObjectPosix_event_st*)event)->RegisteredWaits.size(); ++i) {
SyncObjectPosix_wfmo_info_st
* info = &((SyncObjectPosix_event_st*)event)->RegisteredWaits[i];

result
= pthread_mutex_lock(&info->Waiter->Mutex);
assert(result
== 0);--info->Waiter->RefCount;
assert(info
->Waiter->RefCount >= 0);if (!info->Waiter->StillWaiting) {bool destroy = info->Waiter->RefCount == 0;
result
= pthread_mutex_unlock(&info->Waiter->Mutex);
assert(result
== 0);if(destroy) {
info
->Waiter->Destroy();delete info->Waiter;
}
continue;
}
if (info->Waiter->WaitAll) {--info->Waiter->Status.EventsLeft;
assert(info
->Waiter->Status.EventsLeft >= 0);//We technically should do i->Waiter->StillWaiting = Waiter->Status.EventsLeft//!= 0 but the only time it'll be equal to zero is if we're the last event, so//no one else will be checking the StillWaiting flag. We're good to go without//it. } else{
info
->Waiter->Status.FiredEvent = info->WaitIndex;
info
->Waiter->StillWaiting = false;
}

result
= pthread_mutex_unlock(&info->Waiter->Mutex);
assert(result
== 0);

result
= pthread_cond_signal(&info->Waiter->CVariable);
assert(result
== 0);
}
((SyncObjectPosix_event_st
*)event)->RegisteredWaits.clear();#endif //WFMOresult= pthread_mutex_unlock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result
== 0);

result
= pthread_cond_broadcast(&((SyncObjectPosix_event_st*)event)->CVariable);
assert(result
== 0);
}
return 0;
}
int ResetEvent(void* event) {int result = pthread_mutex_lock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result
== 0);

((SyncObjectPosix_event_st
*)event)->State = false;

result
= pthread_mutex_unlock(&((SyncObjectPosix_event_st*)event)->Mutex);
assert(result
== 0);return 0;
}

#ifdef PULSE
int PulseEvent(void* event) {//This may look like it's a horribly inefficient kludge with the sole intention of reducing//code duplication, but in reality this is what any PulseEvent() implementation must look//like. The only overhead (function calls aside, which your compiler will likely optimize//away, anyway), is if only WFMO auto-reset waits are active there will be overhead to//unnecessarily obtain the event mutex for ResetEvent() after. In all other cases (being no//pending waits, WFMO manual-reset waits, or any WFSO waits), the event mutex must first be//released for the waiting thread to resume action prior to locking the mutex again in//order to set the event state to unsignaled, or else the waiting threads will loop back//into a wait (due to checks for spurious CVariable wakeups). int result = SetEvent(event);
assert(result
== 0);
result
= ResetEvent(event);
assert(result
== 0);return 0;
}
#endif #else#include<mutex>#include<condition_variable>#include<chrono>#include<functional> classSyncObjectPosix
{
public:
SyncObjectPosix(
bool initial, boolmanual) :
state(initial), manual(manual)
{
}
void change(boolmanual)
{
std::unique_lock
<std::mutex> lock(mutex);this->manual =manual;
}
void set()
{
std::unique_lock
<std::mutex> lock(mutex);if(state)return;

state
= true;if(manual)
condition.notify_all();
elsecondition.notify_one();
}
voidreset()
{
std::unique_lock
<std::mutex> lock(mutex);

state
= false;
}
voidwait()
{
std::unique_lock
<std::mutex> lock(mutex);

condition.wait(
lock, [this] { returnstate; });if (!manual)
state
= false;
}

template
<class Rep, class Period> int wait(const std::chrono::duration<Rep, Period> &timeout)
{
std::unique_lock
<std::mutex> lock(mutex);if (!condition.wait_for(lock, timeout, [this] {returnstate;} )) {returnWAIT_TIMEOUT;
}
//return; if (!manual)
state
= false;return 0;
}
private:boolreturn_state() {returnstate;
};

std::mutex mutex;
std::condition_variable condition;
boolstate, manual;
};

inline
void* CreateEvent(void* lpEventAttributes, BOOL bManualReset, BOOL bInitialState, void*lpName){return (void*)(newSyncObjectPosix(bInitialState, bManualReset));
}

inline
void CloseHandle(void*p_this) {delete (SyncObjectPosix*)p_this;
}

inline
int WaitForSingleObject(void* p_this, uint64_t milliseconds = -1){
SyncObjectPosix
* event_this = (SyncObjectPosix*)p_this;return event_this->wait(std::chrono::milliseconds(milliseconds));
}

inline
int SetEvent(void*p_this){
SyncObjectPosix
* event_this = (SyncObjectPosix*)p_this;
event_this
->set();return 0;
}

inline
int ResetEvent(void*p_this){
SyncObjectPosix
* event_this = (SyncObjectPosix*)p_this;
event_this
->reset();return 0;
}
#endif

 

换了一个电脑,跟随潮流,CPU是不带集显的,操作系统从原来的硬盘一通搬过来的

其中Deepin Linux更新到15.11。

显卡是2060的,在Deepin中目前只集成了390的nvidia驱动,无法支持

而nouveu驱动也是个残废,只支持到10xx系统,结果系统驱动在不知道什么模式下,反正屏幕卡得一逼,没法用

找了两天网上资料,反正是没几个讲明白了。有装nvidia官方驱动,有修复就OK了。反正在我的电脑上不行。

不得以,自己搜索了一下deb的安装包,还好debian提供了experments的驱动,下载下来手动安装呗

步骤0:主要从下面地址下载nvidia 435的驱动(安装过程中,有些其他依赖,需要分别去找)

http://mirrors.ustc.edu.cn/debian/pool/non-free/n/nvidia-graphics-drivers/

通常搜索依赖库,可以在这儿:

https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=libxnvctrl0

最后的keywords,就是相关包名,搜索到,点点点,点到下载地址,

下载好相关包后,依次执行如下手工安装包的命令:

1. install glx-alternativessudo dpkg -i glx-alternative-nvidia_1.0.0_amd64.deb glx-diversions_1.0.0_amd64.deb update-glx_1.0.0_amd64.deb glx-alternative-mesa_1.0.0_amd64.deb2. install nvidia-kernel-dkmssudo dpkg -i nvidia-kernel-dkms_435.21-1_amd64.deb nvidia-kernel-support_435.21-1_amd64.deb nvidia-alternative_435.21-1_amd64.deb3. installlib packagesudo dpkg -i libnvidia-eglcore_435.21-1_i386.deb libnvidia-eglcore_435.21-1_amd64.debsudo dpkg -i nvidia-egl-icd_435.21-1_amd64.deb nvidia-egl-icd_435.21-1_i386.deb libegl-nvidia0_435.21-1_amd64.deb libegl-nvidia0_435.21-1_i386.deb4. install nvidia-driversudo dpkg -i nvidia-driver_435.21-1_amd64.deb nvidia-vdpau-driver_435.21-1_amd64.deb xserver-xorg-video-nvidia_435.21-1_amd64.deb nvidia-driver-libs_435.21-1_amd64.deb nvidia-driver-bin_435.21-1_amd64.deb libnvidia-glcore_435.21-1_amd64.deb libgl1-nvidia-glvnd-glx_435.21-1_amd64.deb nvidia-egl-icd_435.21-1_amd64.deb libnvidia-glcore_435.21-1_amd64.deb libnvidia-glcore_435.21-1_i386.deb libgl1-nvidia-glvnd-glx_435.21-1_i386.deb libglx-nvidia0_435.21-1_amd64.deb nvidia-egl-icd_435.21-1_i386.deb libglx-nvidia0_435.21-1_i386.deb libegl-nvidia0_435.21-1_i386.deb5. installutilssudo dpkg -i nvidia-vulkan-icd_435.21-1_amd64.deb nvidia-vulkan-icd_435.21-1_i386.deb nvidia-settings_418.74-1_amd64.deb nvidia-modprobe_418.56-1_bpo9+1_amd64.deb nvidia-detect_435.21-1_amd64.deb libnvidia-ml1_435.21-1_amd64.deb  libnvidia-egl-wayland1_1.1.3-1_amd64.deb libnvidia-cfg1_435.21-1_amd64.deb libgles-nvidia2_435.21-1_amd64.deb libgles-nvidia2_435.21-1_i386.deb libxnvctrl0_418.74-1_i386.deb libxnvctrl0_418.74-1_amd64.deb libnvidia-glvkspirv_435.21-1_amd64.deb libnvidia-glvkspirv_435.21-1_i386.deb6. removesudo apt remove nvidia-persistenced

安装过程中,如果缺包,则搜索/下载相应包

然后重启机器,显卡就已经驱动正常了。

完成后,可以执行如下命令

apt list --installed | grep nvidia

查看当前系统中nvidia相关的包名是否都是新版本了,防止异常问题,最好所有相关包都更新到4xx最新版本来

 

参考:

https://en.cppreference.com/w/cpp/named_req/Allocator

http://www.josuttis.com/libbook/memory/myalloc.hpp.html

 

template <class T>
   classMyAlloc {public://type definitions
typedef T        value_type;
typedef T
*pointer;
typedef
const T*const_pointer;
typedef T
&reference;
typedef
const T&const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//rebind allocator to type U template <class U> structrebind {
typedef MyAlloc
<U>other;
};
//return address of values pointer address (reference value) const{return &value;
}
const_pointer address (const_reference value)
const{return &value;
}
/*constructors and destructor
* - nothing to do because the allocator has no state
*/MyAlloc()throw() {
}
MyAlloc(
const MyAlloc&) throw() {
}
template
<class U>MyAlloc (const MyAlloc<U>&) throw() {
}
~MyAlloc() throw() {
}
//return maximum number of elements that can be allocated size_type max_size () const throw() {return std::numeric_limits<std::size_t>::max() / sizeof(T);
}
//allocate but don't initialize num elements of type T pointer allocate (size_type num, const void* = 0) {//print message and allocate memory with global new pointer ret = (pointer)(malloc(num*sizeof(T)));returnret;
}
//initialize elements of allocated storage p with value value void construct (pointer p, const T&value) {//initialize memory with placement new new((void*)p)T(value);
}
//destroy elements of initialized storage p voiddestroy (pointer p) {//destroy objects by calling their destructor p->~T();
}
//deallocate storage p of deleted elements voiddeallocate (pointer p, size_type num) {
free((
void*)p);
}
};
//return that all specializations of this allocator are interchangeable template <class T1, class T2> bool operator== (const MyAlloc<T1>&,const MyAlloc<T2>&) throw() {return true;
}
template
<class T1, class T2> bool operator!= (const MyAlloc<T1>&,const MyAlloc<T2>&) throw() {return false;
}

 

一个简单的桩实现类:

#define JMPCODE_LENGTH 5            //x86 平坦内存模式下,绝对跳转指令长度
#define JMPCMD_LENGTH  1            //机械码0xe9长度
#define JMPCMD         0xe9         //对应汇编的jmp指令

//一个简化的打桩类的实现
classXSimpleStub
{
public:explicit XSimpleStub(void* pOrigFunc, void* pNewFunc, bool need_lock_other_thread = false);~XSimpleStub();private://源函数地址 void *str_func_addr;//是否打桩成功 boolis_stub_succ;//是否打桩成功 boolneed_lock_other_thread_;//源指令数据的备份 unsigned charstr_instruct_back[JMPCODE_LENGTH];
};

函数就只有两个函数体,分别如下

#include <tlhelp32.h>BOOL LockOtherThread()
{
DWORD dwCurrPid
=GetCurrentProcessId();
DWORD dwCurrTid
=GetCurrentThreadId();

HANDLE hThread
=NULL;
HANDLE hThreadSnap
=NULL;
THREADENTRY32 te32
= { 0};
te32.dwSize
= sizeof(THREADENTRY32);//遍历线程 if (Thread32First(hThreadSnap, &te32))
{
do{if (te32.th32OwnerProcessID ==dwCurrPid) {if (te32.th32ThreadID !=dwCurrTid){//获取句柄 hThread =OpenThread(THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID);if (NULL !=hThread){
SuspendThread(hThread);
}
CloseHandle(hThread);
}
}
}
while (Thread32Next(hThreadSnap, &te32));
}
CloseHandle(hThreadSnap);
returnTRUE;
}

BOOL UnlockOtherThread()
{
DWORD dwCurrPid
=GetCurrentProcessId();
DWORD dwCurrTid
=GetCurrentThreadId();

HANDLE hThread
=NULL;
HANDLE hThreadSnap
=NULL;
THREADENTRY32 te32
= { 0};
te32.dwSize
= sizeof(THREADENTRY32);//遍历线程 if (Thread32First(hThreadSnap, &te32))
{
do{if (te32.th32OwnerProcessID ==dwCurrPid) {if (te32.th32ThreadID !=dwCurrTid){//获取句柄 hThread =OpenThread(THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID);if (NULL !=hThread){
ResumeThread(hThread);
}
CloseHandle(hThread);
}
}
}
while (Thread32Next(hThreadSnap, &te32));
}
CloseHandle(hThreadSnap);
returnTRUE;
}
static void __inner_memcpy(unsigned char* pDest, unsigned char* pSrc, unsigned intcount)
{
while(count > 0) {*pDest++ = *pSrc++;
count
--;
}
}

XSimpleStub::XSimpleStub(
void* pOrigFunc, void* pNewFunc, boolneed_lock_other_thread):
str_func_addr(pOrigFunc), is_stub_succ(
false), need_lock_other_thread_(need_lock_other_thread)
{
//源地址、目标地址需要进行一次判定 if (nullptr != pOrigFunc && nullptr !=pNewFunc)
{
DWORD ProtectVar;
//保护属性变量 MEMORY_BASIC_INFORMATION MemInfo; //内存分页属性信息//取得对应内存的原始属性 if (0 != VirtualQuery(pOrigFunc, &MemInfo, sizeof(MEMORY_BASIC_INFORMATION)))
{
//如果需要锁住所有其他线程,则先执行锁定动作 if(need_lock_other_thread) {
LockOtherThread();
}
//修改页面为可写 if(VirtualProtect(MemInfo.BaseAddress, MemInfo.RegionSize, PAGE_READWRITE, &MemInfo.Protect))
{
//备份原数据,防止自身需要使用memcpy,不能使用类似接口 __inner_memcpy((unsigned char*)str_instruct_back, (unsigned char*)pOrigFunc, JMPCODE_LENGTH);//修改目标地址指令为 jmp pDestFunc *(unsigned char*)pOrigFunc = JMPCMD; //拦截API,在函数代码段前面注入jmp xxx *(DWORD*)((unsigned char*)pOrigFunc + JMPCMD_LENGTH) = (DWORD)pNewFunc - (DWORD)pOrigFunc -JMPCODE_LENGTH;//改回原属性 VirtualProtect(MemInfo.BaseAddress, MemInfo.RegionSize, MemInfo.Protect, &ProtectVar);//修改后,还需要刷新cache FlushInstructionCache(GetCurrentProcess(), pOrigFunc, JMPCODE_LENGTH);

is_stub_succ
= true;
}
//如果需要锁住所有其他线程,则先执行锁定动作 if(need_lock_other_thread) {
UnlockOtherThread();
}
}
}
}

XSimpleStub::
~XSimpleStub()
{
if(is_stub_succ)
{
DWORD TempProtectVar;
//临时保护属性变量 MEMORY_BASIC_INFORMATION MemInfo; //内存分页属性信息 if (0 != VirtualQuery(str_func_addr, &MemInfo, sizeof(MEMORY_BASIC_INFORMATION)))
{
//如果需要锁住所有其他线程,则先执行锁定动作 if(need_lock_other_thread_) {
LockOtherThread();
}
//修改页面为可写 if(VirtualProtect(MemInfo.BaseAddress,MemInfo.RegionSize, PAGE_READWRITE,&MemInfo.Protect))
{
//恢复代码段 __inner_memcpy((unsigned char*)str_func_addr, (unsigned char*)str_instruct_back, JMPCODE_LENGTH);//改回原属性 VirtualProtect(MemInfo.BaseAddress,MemInfo.RegionSize, MemInfo.Protect,&TempProtectVar);//修改后,还需要刷新cache FlushInstructionCache(GetCurrentProcess(), str_func_addr, JMPCODE_LENGTH);
}
//如果需要锁住所有其他线程,则先执行锁定动作 if(need_lock_other_thread_) {
UnlockOtherThread();
}
}
}

}

 

Linux下一样有类似技术,可以参考IBM的一个文档:

https://www.ibm.com/developerworks/cn/linux/l-knldebug/index.html

这其中的差别在跳转指针的设计上,Linux上,是使用了7个字节,并不需要计算原函数、新函数的地址距离

整个替换流程的实现分为如下几个步骤:

1) 替换指令码:
b8
00 00 00 00 /*movl $0, $eax;这里的$0将被具体替换函数的地址所取代*/
ff e0 /*
jmp*$eax ;跳转函数*/
将上述7个指令码存放在一个字符数组中:
replace_code[
7]

2) 用替换函数的地址覆盖第一条指令中的后面8个0,并保留原来的指令码:
memcpy (orig_code, func,
7);/* 保留原函数的指令码 */ *((long*)&replace_code[1])= (long) replace_func;/* 赋替换函数的地址 */ memcpy (func, replace_code, 7); /* 用新的指令码替换原函数指令码 */

3) 恢复过程用保留的指令码覆盖原函数代码:
memcpy (func, orig_code,
7)

Linux下,实现代码页属性修改使用函数接口:mprotect

 而相应的Linux下线程挂起、恢复使用如下接口:

#include <signal.h>
pthread_kill(ThreadID, SIGSTOP);  // suspend
pthread_kill(ThreadID, SIGCONT);  // resume

通过查看/proc/pid/task得知一个任务下的所有线程数