技术标签: libevent源码分析 libevent
typedef struct min_heap
{
struct event** p;
unsigned n, a;
} min_heap_t;
在之前介绍堆的时候已经说过了,表示堆的数组包括两个属性。libevent的最小堆通用遵循。成员p表示的就是堆的数组(其实就是一个动态分配的数组)、成员n表示有多少个堆元素存储在数组中、成员a表示数据的大小(动态分配内存的大小)。
void min_heap_ctor_(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; } //构造(初始化)一个最小堆
void min_heap_dtor_(min_heap_t* s) { if (s->p) mm_free(s->p); } //析构(释放)一个最小堆
void min_heap_elem_init_(struct event* e) { e->ev_timeout_pos.min_heap_idx = -1; } //初始化最小堆的成员变量
int min_heap_empty_(min_heap_t* s) { return 0u == s->n; } //判断最小堆是否为空
unsigned min_heap_size_(min_heap_t* s) { return s->n; } //获取最小堆的大小
struct event* min_heap_top_(min_heap_t* s) { return s->n ? *s->p : 0; } //获取最小堆的根结点
这些操作相对简单,这里就是不对这些操作进行分析了。
/** Return true iff the tvp is related to uvp according to the relational
* operator cmp. Recognized values for cmp are ==, <=, <, >=, and >. */
#define evutil_timercmp(tvp, uvp, cmp) \
(((tvp)->tv_sec == (uvp)->tv_sec) ? \
((tvp)->tv_usec cmp (uvp)->tv_usec) : \
((tvp)->tv_sec cmp (uvp)->tv_sec))
#define min_heap_elem_greater(a, b) \
(evutil_timercmp(&(a)->ev_timeout, &(b)->ev_timeout, >))
这个宏用于比较两个超时值,如果a的超时值大于b的超时值则返回真,否则反正false。
//这个函数的作用是根据n决定是否重新分配最小堆数组的大小
int min_heap_reserve_(min_heap_t* s, unsigned n)
{
//如果数组的容量还够,直接返回
if (s->a < n)
{
struct event** p;
//如果最小堆数组的大小不为0,则重新动态分配的大小为原先大小的2倍
//否则,只分配数组大小为8
unsigned a = s->a ? s->a * 2 : 8;
//调用分配算法之后,还是不够,需要在作调整
if (a < n)
a = n;
if (!(p = (struct event**)mm_realloc(s->p, a * sizeof *p)))
return -1;
s->p = p; //重新分配之后最小堆的数组
s->a = a; //重新分配之后最小堆的大小
}
return 0;
}
//将某个叶子结点的堆元素上浮到合适的位置,用于堆元素的插入 void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e) { unsigned parent = (hole_index - 1) / 2; //根据最小堆中堆元素的个数,计算出要插入节点e的父结点的下标 //如果hole_index等于0,也就是说最小堆为空,那么就不会进入while,e就是根结点了 //否则,e就与其父节点比较 while (hole_index && min_heap_elem_greater(s->p[parent], e)) { //如果父节点大于e,显然是不符合最小堆的定义,那么就移动父节点到新的下标上 //仅紧接着看e是否能放到原先父节点的位置上,其实就是继续和父节点比较 (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index; hole_index = parent; parent = (hole_index - 1) / 2; } //已经找到适合放置e了 (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index; }
//将某个叶子结点的堆元素下浮到合适的位置,用于堆元素的取出 void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e) { unsigned min_child = 2 * (hole_index + 1); //下标为hole_index的右孩子的下标 //如果对应的hole_index左右孩子,那么取出hole_index就简单了 while (min_child <= s->n) { //根据运算符的优先级,我们可以知道表达式(min_child == s->n)先计算, //该 表达式为真表示hole_index仅有左孩子,也就不会再计算后面表达的值。 //否则,就以看右孩子是否大于左孩子,如果是整个表达式为真(1) //那么整个表达式就很清晰了:用于计算hole_index左右子结点最小的那个 min_child -= ((min_child == s->n) || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1])); if (!(min_heap_elem_greater(e, s->p[min_child]))) break; //把e放到hole_index下标能符合最小堆的定义,就不需要下浮了 //否则,把左右子结点中最小的放入hole_index下标的位置,然后继续看空出的位置是否能 //放入e满足最小堆的定义,不行就进行 下浮。 (s->p[hole_index] = s->p[min_child])->ev_timeout_pos.min_heap_idx = hole_index; hole_index = min_child; min_child = 2 * (hole_index + 1); } (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index; }
//和min_heap_shift_up_类似,只是一次无条件上浮 void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e) { unsigned parent = (hole_index - 1) / 2; do { (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index; hole_index = parent; parent = (hole_index - 1) / 2; } while (hole_index && min_heap_elem_greater(s->p[parent], e)); (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index; }
//向最小堆中插入一个对元素
int min_heap_push_(min_heap_t* s, struct event* e)
{
//最小堆空间是否足够,不够则进行分配
if (min_heap_reserve_(s, s->n + 1))
return -1;
//将要放入的最小堆的堆元素放到,最小堆数组的最后面,然后上浮到对应的位置
min_heap_shift_up_(s, s->n++, e);
return 0;
}
//取出最小堆的根结点
struct event* min_heap_pop_(min_heap_t* s)
{
//最小堆为空,则返回MILL
if (s->n)
{
struct event* e = *s->p; //取出最小堆的根结点
//将最小堆最后的堆元素放入到根结点的位置并进行下浮
min_heap_shift_down_(s, 0u, s->p[--s->n]);
e->ev_timeout_pos.min_heap_idx = -1;
return e;
}
return 0;
}
//判断某个堆元素是否是跟结点
int min_heap_elt_is_top_(const struct event *e)
{
return e->ev_timeout_pos.min_heap_idx == 0;
}
//在最小堆中销毁e,并用堆的最后一个堆元素进行替换和调整
int min_heap_erase_(min_heap_t* s, struct event* e)
{
if (-1 != e->ev_timeout_pos.min_heap_idx)
{
struct event *last = s->p[--s->n]; //取出最后一个堆元素
unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2; //e的父结点
/* we replace e with the last element in the heap. We might need to
shift it upward if it is less than its parent, or downward if it is
greater than one or both its children. Since the children are known
to be less than the parent, it can't need to shift both up and
down. */
//如果e不是根结点,并且准备销毁的结点的父节点比最后一个堆元素大(不符合最小堆),那么
//就进行上浮(用于无条件上浮,确保被销毁),否则就需要下浮
if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, last);
else
min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, last);
e->ev_timeout_pos.min_heap_idx = -1;
return 0;
}
return -1;
}
//调整e在最下堆的位置,e可能是堆中原本的堆元素或不是堆元素
int min_heap_adjust_(min_heap_t *s, struct event *e)
{
if (-1 == e->ev_timeout_pos.min_heap_idx) {
//如果e不是堆元素,则直接添加到堆中去
return min_heap_push_(s, e);
} else {
//否则就看e是否符合最小堆,不符合就需要进行上浮或下浮操作
unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2;
/* The position of e has changed; we shift it up or down
* as needed. We can't need to do both. */
if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], e))
min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, e);
else
min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, e);
return 0;
}
}
//重新分配最小堆的大小(整个最小堆数组的大小)
int min_heap_reserve_(min_heap_t* s, unsigned n)
{
if (s->a < n)
{
struct event** p;
unsigned a = s->a ? s->a * 2 : 8;
if (a < n)
a = n;
if (!(p = (struct event**)mm_realloc(s->p, a * sizeof *p)))
return -1;
s->p = p;
s->a = a;
}
return 0;
}
#ifndef __MIN_HEAP_H__
#define __MIN_HEAP_H__
typedef bool(*FuncCmp)(void *, void *);
template<typename T>
class CMinHeap
{
public:
explicit CMinHeap(FuncCmp CallBack)
:m_pMinHeap(NULL)
,m_iHeapMaxSize(0)
,m_iHeapCurrentSize(0)
,m_MinHeapCallBack(CallBack)
{
}
~CMinHeap()
{
if (m_pMinHeap)
delete[] m_pMinHeap;
}
bool empty(void)
{
return m_iHeapCurrentSize == 0;
}
int push(T elem)
{
if (reserve(m_iHeapCurrentSize + 1))
return -1;
shift_up(m_iHeapCurrentSize++, elem);
return 0;
}
T pop(void)
{
if (m_iHeapCurrentSize)
{
T Elem = *m_pMinHeap;
shift_down(0, m_pMinHeap[--m_iHeapCurrentSize]);
return Elem;
}
return NULL;
}
private:
int reserve(unsigned uiSize)
{
if (m_iHeapMaxSize < uiSize)
{
T *pTemp;
unsigned uiReserveSize = m_iHeapMaxSize ? m_iHeapMaxSize * 2 : 8;
if (uiReserveSize < uiSize)
uiReserveSize = uiSize;
if (!(pTemp = new T[uiReserveSize]))
return -1;
m_pMinHeap = pTemp;
m_iHeapMaxSize = uiReserveSize;
}
return 0;
}
void shift_up(unsigned uiHoleIndex, T Elem)
{
unsigned uiParent = (uiHoleIndex - 1) / 2;
while (uiHoleIndex && m_MinHeapCallBack && m_MinHeapCallBack(m_pMinHeap[uiParent], Elem))
{
m_pMinHeap[uiHoleIndex] = m_pMinHeap[uiParent];
uiHoleIndex = uiParent;
uiParent = (uiHoleIndex - 1) / 2;
}
m_pMinHeap[uiHoleIndex] = Elem;
}
void shift_down(unsigned uiHoleIndex, T Elem)
{
unsigned uiMinChild = 2 * (uiHoleIndex + 1);
while (uiMinChild <= m_iHeapCurrentSize)
{
uiMinChild -= ((uiMinChild == m_iHeapCurrentSize) || m_MinHeapCallBack(m_pMinHeap[uiMinChild], m_pMinHeap[uiMinChild - 1]));
if (!m_MinHeapCallBack(Elem, m_pMinHeap[uiMinChild]))
break;
m_pMinHeap[uiHoleIndex] = m_pMinHeap[uiMinChild];
uiHoleIndex = uiMinChild;
uiMinChild = 2 * (uiHoleIndex + 1);
}
m_pMinHeap[uiHoleIndex] = Elem;
}
T *m_pMinHeap;
unsigned int m_iHeapMaxSize;
unsigned int m_iHeapCurrentSize;
FuncCmp m_MinHeapCallBack;
};
#endif //#ifndef __MIN_HEAP_H__
main.cpp
#include <iostream>
#include "min_heap.h"
using namespace std;
bool eventTimeCmp(void *pElem1, void *pElem2);
class Event
{
public:
Event(int iTimeout)
:m_iTimeOut(iTimeout)
{
}
~Event() { }
void play(void)
{
cout << "m_iTimeOut = " << m_iTimeOut << endl;
}
private:
friend bool eventTimeCmp(void *pElem1, void *pElem2);
int m_iTimeOut;
};
bool eventTimeCmp(void *pElem1, void *pElem2)
{
Event *pEvent1 = static_cast<Event *>(pElem1);
Event *pEvent2 = static_cast<Event *>(pElem2);
return pEvent1->m_iTimeOut > pEvent2->m_iTimeOut;
}
int main(void)
{
CMinHeap<Event *> Heap(eventTimeCmp);
Event *pEvent1 = new Event(2);
Event *pEvent2 = new Event(4);
Event *pEvent3 = new Event(6);
Event *pEvent4 = new Event(8);
Event *pEvent5 = new Event(10);
Heap.push(pEvent3);
Heap.push(pEvent1);
Heap.push(pEvent5);
Heap.push(pEvent2);
Heap.push(pEvent4);
Event *pTemp;
while (!Heap.empty())
{
pTemp = Heap.pop();
pTemp->play();
}
delete pEvent1;
delete pEvent2;
delete pEvent3;
delete pEvent4;
delete pEvent5;
return 0;
}
运行结果:
m_iTimeOut = 2
m_iTimeOut = 4
m_iTimeOut = 6
m_iTimeOut = 8
m_iTimeOut = 10
0x01 影响版本:致远A8-V5协同管理软件 V6.1sp1致远A8+协同管理软件 V7.0、V7.0sp1、V7.0sp2、V7.0sp3致远A8+协同管理软件 V7.10x02 漏洞利用:01.通过访问/seeyon/htmlofficeservlet如果出现下图则可能存在在通过我更改过的脚本进行检测确认目标存在可写入漏洞并且访问已写入的文件url,如图接下来程序会询问是否接着尝试getshell如果确定会得到exp的利用urlpython脚本:https://github.
1) 纵向导航菜单body { font-family: Verdana;font-size: 12px; line-height: 1.5; }a { color: #000;text-decoration: none; }a:hover { color: #F00; }#menu { width: 100px; border:1px solid #CCC; }#menu
7-20表达式转换(25分)算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。日常使用的算术表达式是采用中缀表示法,即二元运算符位于两个运算数中间。请设计程序将中缀表达式转换为后缀表达式。输入格式:输入在一行中给出不含空格的中缀表达式,可包含+、-、*、\以及左右括号(),表达式不超过20个字符。输出格式:在一行中输出转换后的后缀表达式,要求不同对象(运算数、运算符号...
习题2-3 求平方与倒数序列的部分和 (15分)#include<stdio.h>int main(){ int m,n,i; double s=0; scanf("%d%d",&m,&n); for(i=m;i<=n;i++) { s+=i*i+1.0/i; } printf("sum = %.6lf",s);}习题2-4 求交错序列前N项和 (15分)#include<stdio.h
Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等等。 所有这些工具每天都在被Google的工程师应用在产品服务中。项目中使用方法,Maven引用<dependenc
Java Agent支持的配置属性TIPS本表格基于Skywalking 6.6.0,官方文档详见:https://github.com/apache/skywalking/blob/v6.6.0/docs/en/setup/service-agent/java-agent/README.md ,其他版本配置项不完全相同,请自行将链接中的 v6.6.0 修改成你所使用的版本。属性名描述默认值agent.namespace命名空间,用于隔离跨进程传播的header。如果进行了
本文内容来自:chrome console的使用 : 异常和错误的处理 – Break易站利用 Chrome DevTools 提供的工具,您可以修复引发异常的网页和在 JavaScript 中调试错误。如果您可以了解背后的详细信息,页面异常和 JavaScript 错误会非常有用。在页面引发异常或脚本产生错误时,Console 可以提供具体、可靠的信息来帮助您定位和纠正问题。
转载自:http://blog.chinaunix.net/uid-25272011-id-3153434.html最近在调试一款原相PAP7501摄像头中的USB的麦克风,USB层走的应该是标准的UAC协议,具体可以见USB的官网:http://www.usb.org/developers/devclass_docs#approved,而音频部分则可以跑目前Linux标准的ALSA的PCM接
蜕变之路立个flag:三年码农,知识体系不健全,立此flag在于鞭策自己,重新构建知识体系。蜕变之路系列文章从算法,java基础,计算机网络,框架,微服务等着手学习。计划一期算法与数据结构每天一篇,四月一个月,进行算法复习...
一、视频加密 视频加密是对某些自有版权的视频进行加密处理,用户只有在一定的条件下才能获得视频的观看权。比如对于教育视频加密后,只有学员才能观看,每个学员都有自己的唯一账号。或者说设定在一定的时间内可以无限次观看...
原文:点击打开链接今天尝试更新了下虚拟机CentOS中的python版本后。运行“yum”命令,就报错:“sudo: unable to execute /bin/yum: No such file or directory”查询了下网上的资料发现,原来yum调用是用python写的。遂想起刚刚更新python版本,忘了修改yum配置文件了。解决办法:修改yum
shell脚本中使用自定义命令之四---通过加载.bashrc实现1、.bashrc文件alias log_success="figlet Success | lolcat && cowsay -f dragon haha |lolcat"alias log_fail="figlet Fail | lolcat && cowsay -f sheep Cry |lolcat"