如何搭建程序复现笔记本芯片在电源状态切换中的死锁问题,必备的抖音seo方案
栏目:网络推广 发布时间:2025-02-27
最近碰到一个问题,是关于芯片测试过程的。这颗芯片被用在笔记本的端口上。笔记本的客户那边会进行一个压力测试,测试内容是频繁地进行电脑电源状态的切换,包括 S0( ... 如何搭建程序复现笔记本芯片在电源状态切换中的死锁问题
    最近碰到一个问题,是关于芯片测试过程的。这颗芯片被用在笔记本的端口上。笔记本的客户那边会进行一个压力测试,测试内容是频繁地进行电脑电源状态的切换,包括 S0(正常使用的开机状态)、S3(睡眠模式)、S4(休眠模式)以及 S5(关机模式)。

    主要是在压力测试过程中,客户发现了芯片会出现不正常的死锁。客户把机台寄了回来,接下来要如何复现呢?客户那边有自己的一套压力测试系统,但是会测试很多东西,不太便于给我们,并且每一次循环耗时比较长。那么,是否可以自己搭建一套能够控制电脑睡眠、休眠、关机以及唤醒的程序呢?

    上面讲述的是一个应用背景,告知大家实际上是存在需求的,只是在平时不太会使用,所以将其记录了下来。

    首先,将电脑从开机状态 S0 切换至 S3 是比较容易实现的。其次,把电脑从开机状态 S0 切换到 S4 也是比较容易实现的。再者,把电脑从开机状态 S0 切换到 S5 同样是比较容易实现的,见下面代码:

<p style='margin-bottom:15px;color:#555555;font-size:15px;line-height:200%;text-indent:2em;'>    <pre class="syl-page-code"><code>Application 设置挂起状态为电源状态挂起(PowerState.Suspend),设置为假(false),设置为假(false);这是从 S0 进入 S3 的操作。
Application 设置挂起状态,状态为电源状态休眠,第二个参数为 false,第三个参数为 false;此操作是从 S0 进入 S4。
Process.Start 函数用于启动一个新进程。其中,第一个参数 "shutdown" 表示要执行的操作是关机。第二个参数 "/s /t 0" 中,"/s" 的意思是要关闭计算机,"/t 0" 表示设置关机的延迟时间为 0 秒,即立即关机。
参数 /t 0 的含义是向计算机传达在 0 秒过后执行命令这一信息。
Process.Start("shutdown", "/r /t 0");  此操作中 /r 参数的含义为要重新启动计算机。</code></pre></p>
    如果调用上述语句就能达成从 S0 到其他电源状态的转变,那么反过来要如何唤醒呢?

    唤醒存在难点。处于 S3、S4 以及 S5 的状态时,我的上位机程序不会运行。所以,上位机软件的定时唤醒无法工作。那么笔记本客户那边是如何操作的呢?他们通过底层的 EC 控制来显示上述功能。然而,我们不知道底层 EC 的接口,并且我们需要一个通用的程式,那该怎么实现呢?

    在笔记本的设计里,S3、S4、S5 通常不是所有东西都会关闭。通常会有一个硬件定时器处于开启状态。如果我们能够操作这个定时器,那么是否就可以实现我们所想要的功能呢?

    可以调用以下两个函数,即某个函数和另一个函数,这两个函数能够控制电脑中所开启的硬件定时器,至于这个硬件定时器究竟是位于 CPU 内部还是 EC 内部,我并不知晓,也未曾进行过研究,如果有精通此领域的大神进行过研究,可以留言,我也可以借此学习学习。

<p style='margin-bottom:15px;color:#555555;font-size:15px;line-height:200%;text-indent:2em;'>    <pre class="syl-page-code"><code>[DllImport("kernel32.dll")]
公共静态外部方法 SafeWaitHandle 创建可等待定时器(IntPtr lpTimerAttributes,布尔值 bManualReset,字符串 lpTimerName);
在“kernel32.dll”中进行 DllImport 操作,并且设置了 SetLastError 为 true 。
[return: MarshalAs 为 UnmanagedType.Bool 的形式]
公共静态外部方法 SetWaitableTimer 接收一个 SafeWaitHandle 类型的参数 hTimer,一个引用类型的 long 类型参数 pDueTime,一个 int 类型的参数 lPeriod,一个 IntPtr 类型的参数 pfnCompletionRoutine,一个 IntPtr 类型的参数 lpArgToCompletionRoutine,以及一个 bool 类型的参数 fResume,并返回一个 bool 值。该方法用于设置可等待定时器。</code></pre></p>
    另外,有一点需要说明,使用这个定时器是有条件的。首先,你得先设置笔记本,即“Panel>Power>Plan>Power>Sleep>Allow Wake”,以实现定时器唤醒功能。其次,“Panel>Power>Plan>Power>Brad/>a on”,这一步是关闭唤醒需要密码。

    完成上述设置后,电脑能够从 S3、S4、S5 唤醒。然而,在我使用的过程中,遇到了一个问题,即唤醒之后屏幕不亮,会让人误以为没有唤醒。所以,我增加了控制鼠标移动的命令,这样一来,唤醒之后屏幕就会亮起。

<p style='margin-bottom:15px;color:#555555;font-size:15px;line-height:200%;text-indent:2em;'>    <pre class="syl-page-code"><code>[DllImport("user32.dll")]
公共静态外部方法 mouse_event,该方法接收一个 32 位整数 dwFlags,一个 32 位整数 dx,一个 32 位整数 dy,一个 32 位整数 dwData,以及一个无符号指针 dwExtraInfo 作为参数。
调用 mouse_event 函数,传入参数 0x0001、0、1、0 和 UIntPtr.Zero,用于模拟鼠标操作。
调用 mouse_event 函数,其参数为 0x0001、0、-1、0 和 UIntPtr.Zero 。 该函数用于模拟鼠标操作,这里的第一个参数 0x0001 可能代表某种特定的鼠标动作。 第二个参数 0 表示鼠标的水平移动量。 第三个参数 -1 表示鼠标的垂直移动量。 第四个参数 0 可能与鼠标的其他相关设置有关。 最后一个参数 UIntPtr.Zero 也可能在鼠标事件的处理中起到特定的作用。</code></pre></p>
    另外需注意,在笔记本从 S0 到 S3/S4/S5 再到 S0 的循环中,S0 以及 S3/S4/S5 这几种状态的停留时间需足够长。因为每台笔记本完全进入各状态的时间不同,例如我自己的笔记本,这些状态的停留时间至少要 20 秒。否则,笔记本尚未完全进入就退出,会致使电脑关机,而此时笔记本还未被唤醒,从而导致程式死锁。而新的刚买的笔记本,只需要设置10s即可完全进入。

    废话不多说,直接上代码:

<p style='margin-bottom:15px;color:#555555;font-size:15px;line-height:200%;text-indent:2em;'>    <pre class="syl-page-code"><code>using System;
系统使用了一系列的集合类型,这些集合类型包含了多个元素,它们共同构成了特定的数据结构,用于存储和管理相关的数据。
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
使用 Microsoft.Win32.SafeHandles 。
System.Runtime.InteropServices 被使用。
namespace AutoSwitchGUI
{
通过这个类可以创建出相应的图形用户界面。
    {
        [DllImport("kernel32.dll")]
公共静态外部方法 SafeWaitHandle 创建可等待定时器(IntPtr lpTimerAttributes,布尔值 bManualReset,字符串 lpTimerName);
在“kernel32.dll”中进行 DllImport 操作,并且设置了 SetLastError 为 true 。
使用 MarshalAs 特性并将其参数设置为 UnmanagedType.Bool 进行返回
公共静态外部方法 SetWaitableTimer 接受一个 SafeWaitHandle 类型的参数 hTimer,以及一个引用类型的 long 类型参数 pDueTime,一个 int 类型的参数 lPeriod,一个 IntPtr 类型的参数 pfnCompletionRoutine,一个 IntPtr 类型的参数 lpArgToCompletionRoutine 和一个 bool 类型的参数 fResume。该方法用于设置等待定时器。
        [DllImport("kernel32.dll")]
公共静态外部函数 SetThreadExecutionState 接收一个 uint 类型的参数 esFlags 并返回一个 uint 值。
        [DllImport("user32.dll")]
公共静态外部方法 mouse_event,它接受一个 32 位整数 dwFlags,一个 32 位整数 dx,一个 32 位整数 dy,一个 32 位整数 dwData,以及一个无符号指针 dwExtraInfo 作为参数。
公共事件 EventHandler 被引发唤醒;
创建了一个私有类型的 BackgroundWorker 对象,名为 bgWorker 。