在之前的Netty之线程唤醒wakeup文章中, 介绍了如何唤醒Netty中的监听线程. . // WakeUp.java import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.Selector ; import java.nio.channels.ServerSocketChannel; import java.net.ServerSocket; public class WakeUp {
前言 在wakeup events framework小节中提到,wakeup events framwork可以解决system suspend和wakeup events之间的同步问题。 所有本小节继续分析wakeup events framework中的重要知识点-wakeup count。 "wakeup count"是不是很熟悉? 是的,在wakeup_source结构体中就存在"wakeup_count"成员,此成员的意思是:终止suspend的次数。而本小节的wakeup count并非此意,只是名字相同罢了。 这时候如果系统发生了wakeup events,就会增加wakeup event的数量。 4. 当系统有wakeup events上报时,调用wakeup events framework的接口active该wakeup source,然后"wakeup event in progress"加1。
在wakeup events framework中重要的数据结构就是wakeup_source,字面意思就是产生wakeup events的设备。 .expire_count: wakeup source timeout次数。 .wakeup_count: wakeup source abort睡眠的次数。 将设备和wakeup source建立连接。如果失败,则释放wakeup source。 wakeup_source_register(分配一个唤醒源,将其加入到wakeup source链表中) struct wakeup_source *wakeup_source_register(const pm_wakeup_event(唤醒wakeup source, 在一段时间之后取消唤醒源) void __pm_wakeup_event(struct wakeup_source *ws, unsigned
@Override protected void wakeup(boolean inEventLoop) { if (! inEventLoop && wakenUp.compareAndSet(false, true)) { // 唤醒IO线程 selector.wakeup(); } } 源码位置: io.netty.channel.nio.NioEventLoop#wakeup 以上代码, 就是唤醒的代码, 主要调用的方法就是wakeup. IO线程调用select方法被阻塞, 非IO线程通过调用wakeup方法将IO线程唤醒. 接下来通过查看它的系统调用, 弄清楚它到底是如何实现的. 环境 1. 当另一个线程调用selector.wakeup()的时候, 它就会向6号文件描述符写入数据, 通过pipe通信的方式, 唤醒另一个阻塞的线程. 可以通过grep搜索关键字write验证结论.
图片中红色边框的block是wakeup events相关的block: 抽象wakeup source和wakeup event的概念; 向各个device driver提供wakeup source 当wakeup source产生wakeup event时,需要将wakeup source切换为activate状态;当wakeup event处理完毕后,要切换为deactivate状态。 当wakeup source产生wakeup event时,会通过wakeup events framework提供的接口将wakeup source设置为activate状态。 ,对于can_wakeup的设备,使能或者禁止wakeup功能。 4)wakeup_abort_count,只读,获取dev->power.wakeup->wakeup_count值。
device_init_wakeup() static inline int device_init_wakeup(struct device *dev, bool val) { device_set_wakeup_capable static inline void device_set_wakeup_capable(struct device *dev, bool capable) { dev->power.can_wakeup = enable; return 0; } 要认识device_init_wakeup(),首先需要知道两个概念:can_wakeup和should_wakeup。 中的电源管理,有责任调用device_init_wakeup()来初始化can_wakeup。 而should_wakeup则是在设备的 电源状态发生变化时 被device_may_wakeup()用来测试,测试它该不该变化。 can_wakeup,标识本设备是否具有唤醒能力。
本文简单介绍了一些 虚假唤醒(spurious wakeup) 相关的知识 (注: 本文假设读者对多线程开发有一定了解) 高层次的多线程编程中,条件变量是个常见的同步方法,跟传统仅使用互斥量的方法相比 g_signaled) { pthread_cond_wait(&g_cond, &g_mutex); } 这么做的一个原因便是为了处理 虚假唤醒(spurious wakeup),
)销毁对象时调用 __toString()把对象转换为字符串,打印一个对象时被调用 __sleep()在序列化前被调用,此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组 __wakeup private属性被序列化的时候属性值会变成:%00类名%00属性名(可是运行结果用空格代替了%00,这一点我也不清楚,因为%00是ASCII转url编码以后对应的空字符吧,还请大佬解答一下) 绕过 __wakeup () 函数 当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行。 > 可以看出传入的username参数值必须为admin,但是它用wakeup函数重新给参数赋值了guest,这里我们直接跳过wakeup函数就行了。 原本对应的序列化后的对象为: O:3:"ctf":2:{s:11:"%00*%00username";s:5:"admin";s:6:"%00*%00cmd";s:2:"ls";} 绕过__wakeup
__wakeup是在反序列化对象的时候调用 4.可以在序列化对象的时候 , 只序列化指定的属性 , 减少序列化后的大小, 要把这个对象字符串存储在比如memcache的时候 ,比较有用 5.比如下面的例子 \r\n"; return array('data'); } public function __wakeup(){ echo "wakeup...
> wakeup_sources.log active_count:对应wakeup source被激活的次数. event_count:被信号唤醒的次数 wakeup_count:中止suspend total_time:对应wakeup source活跃的总时长. max_time:对应的wakeup source持续活跃最长的一次时间. last_change:上一次wakeup source 的wakeup sources. 如果测试前后,都有捉 wakeup_sources.log 请对两份wakeup_sources.log的total time的差值. 差值时间跟灭屏的时间对得上,一般就是这个锁引起的问题. 把捉出来的wakeup_sources.log复制到excel表格中,比较好对齐,一个是比较好计算.
前言 本文主要讲述一个概念:虚假唤醒(spurious wakeup)。 在并发编程中,我们可能在实践中并没有遇到过,但是它确实存在,概率较低,但一旦出现,问题就非常的大。
1.前言:总结一下序列化和反序列化的入门知识 __sleep 与 __wakeup 序列化: 将一个对象转化成字符串 反序列化:将一个字符串转换成对象 2.魔术方法: __construct: 在创建对象时候初始化对象 __sleep:序列化对象之前就调用此方法(其返回需要一个数组) __wakeup:反序列化恢复对象之前调用该方法 __call:当调用对象中不存在的方法会自动调用该方法。 ,反序列化时,会优先检查是否存在__wakeup魔术方法,如果存在,就会优先调用__wakeup方法 <? 6.例题(来源XCTF) class xctf{ public $flag = '111'; public function __wakeup(){ exit('bad requests'); } ? __wakeup,因为你构造的属性和真实的属性不符; 但修改属性值是不会绕过__wakeup的,所以综述:只有改变属性个数、属性类型、属性名才可以绕过!
}
function __sleep()
{
$arr=array("name","age");//这样做是删除掉sex变量
return($arr);
}
function __wakeup $p1_string;
echo "
";
$p2=unserialize($p1_string);//反串行化,调用__wakeup在转换成对象(过程中)
$p2->say();
?>
这时候wakeup event framework的出现就可以解决此问题,当系统中没有wakeup event事件的时候,就尝试系统suspend。 当系统中没有wakeup event事件发生的时候,就可以尝试suspend,需要wakeup event framework机制支持。 3. 调用pm_get_wakeup_count函数获取系统的wakeup count数量,存放到initial_count变量中。 2. 调用pm_save_wakeup_count函数存放到saved_count变量中,如果失败,说明有wakeup event发生。跳到out处重新提交,重新来过。 3. 在系统产生wakeup event之后,唤醒系统之后再次读取wakeup count的数量。 5. 如果读取数量和suspend保存的一样,说明有不明原因唤醒系统。
的执行,何为wakeup呢? __wakeup是PHP中的一个魔术方法,如果在反序列化一个类的时候,会先检查是否有__wakeup的存在,有的话,会先调用wakeup里面的内容 利用 版本限制 PHP5:<5.6.25 PHP7:< 7.0.10 代码 class vFREE{ public $name='vFREE'; public $age='18'; function __wakeup(){ $this 方法,有的话就执行,没有就跳过,很明显,代码中有wakeup,但是wakeup的内容就是一个赋值操作,并起不了太大的作用,反而destruct中可以利用一波,因为destruct中打开一个flag.php >一共有18个字符,所以,数值要随着字符数的变化而变化,然后传入即可 当然,此时还是会先执行wakeup方法的,并未先执行destruct,根据开头讲的,更改原有属性值达到绕过过wakeup的效果,此时的类中属性值是
和wakeup event之间的同步问题之后。 新wakelock 基于wakeup event framework机制。 wakelock就是在kernel space激活一个wakeup event。 .ws: 该wakelock对应的wakeup source。因为wakelock就是一个user space的wakeup source。 如果该wakelock有超时时间,则调用__pm_wakeup_event函数上报一个timeout_ns的wakeup events。 重新分配一个新的wakelock,设置wakelock, wakeup source的name,调用wakeup_source_add接口将此wakeup source加入到系统中。 4.
9 6 2 2 1>; (2) label = "wakeup"; linux,code = <KEY_WAKEUP>; }; }; 1.wakeup-source WAKEUP_SRC is as follow: CPUS_WAKEUP_LOWBATT bit 0x1000 CPUS_WAKEUP_USB bit 0x2000 CPUS_WAKEUP_AC bit 0x4000 CPUS_WAKEUP_ASCEND bit 0x8000 CPUS_WAKEUP_DESCEND bit 0x10000 CPUS_WAKEUP_IR bit 0x80000 CPUS_WAKEUP_ALM0 ) #define CPUS_WAKEUP_SHORT_KEY (1<<17) #define CPUS_WAKEUP_LONG_KEY (1<<18) #define CPUS_WAKEUP_IR ( (1<<31) #define CPUS_WAKEUP_KEY (CPUS_WAKEUP_SHORT_KEY | CPUS_WAKEUP_LONG_KEY) 查看关键打印: platform wakeup
events framework提供的wakeup source机制,实现用户空间的wakeup source(就是wakelocks),并通过PM core main模块,向用户空间提供两个同名的sysfs 而Kernel的wakelock,是基于wakeup source实现的,因此创建wakelock的本质是在指定的wakeup source上activate一个wakeup event,注销wakelock 的本质是deactivate wakeup event。 source为参数调用__pm_stay_awake(或者__pm_wakeup_event),即activate wakeup event; 写wake_unlock(以wakelock name为参数 注1:上面有关wakeup source的操作接口,可参考“Linux电源管理(7)_Wakeup events framework”。
= false; // 醒来的行为 public void wakeUp() { this.wakeup = true; } public boolean isWakeup () { return wakeup; } public void setWakeup(boolean wakeup) { this.wakeup = wakeup 在wakeUp方法中增加,通知母亲的逻辑 public void wakeUp() { wakeup = true; this.mother.feed(this); } public boolean isWakeup() { return wakeup; } public void setWakeup(boolean wakeup ) { this.wakeup = wakeup; } //3.
19 一般情况下,使用 AlarmManager 来执行重复定时任务的代码如下所示: alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP 第一个参数表示闹钟类型:一般为 AlarmManager.ELAPSED_REALTIME_WAKEUP 或者 AlarmManager.RTC_WAKEUP 。 所以如果设置为 AlarmManager.RTC_WAKEUP ,那么可以通过修改手机系统的时间来提前触发定时事件。 第一个参数若为 AlarmManager.ELAPSED_REALTIME_WAKEUP ,那么当前时间就为 SystemClock.elapsedRealtime() ;若为 AlarmManager.RTC_WAKEUP = Build.VERSION_CODES.M) { alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP