NuttX的学习笔记 13
2.6 Clocks and Timers
这部分是时钟与定时器,ostest
里面并没有发现相关东西,在例子里找到了timer
,在configure
里开启这个例子。
查看这个例子的Kconfig
文件,开头是这么写的:
config EXAMPLES_TIMER
bool "Timer example"
default n
depends on TIMER && BUILD_FLAT
---help---
Enable the timer example
这个例子配置标志为EXAMPLES_TIMER
,而该标志依赖于TIMER
和BUILD_FLAT
,Timer
的位置是:
>Device Drivers > Timer Driver Support
BUILD_FLAT
的位置是:
>Build Setup > Build Configuration
因为现在正在跑的就是平坦型,所以第二个就是y,只要打开第一个就可以了。现在就可以打开定时器例子了。
退出编译timer
会得到错误的提示:
Open /dev/timer0
ERROR: Failed to open /dev/timer0: 2
看起来还需要设定这个定时器。
这个定时器应该的设定方法四处寻找并没有找到,到构架里看看tim头文件吧。
nuttx\arch\arm\src\stm32l4\stm32l4_tim.h
/****************************************************************************
* Name: stm32l4_timer_initialize
*
* Description:
* Bind the configuration timer to a timer lower half instance and
* register the timer drivers at 'devpath'
*
* Input Parameters:
* devpath - The full path to the timer device. This should be of the form /dev/timer0
* timer - the timer number.
*
* Returned Value:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
#ifdef CONFIG_TIMER
int stm32l4_timer_initialize(FAR const char *devpath, int timer);
#endif
这里有一个声明,然而我并没有找到定义,先试试看吧,就用定时器0。
把这些加在nuttx\configs\b-l475e-iot01a\src\stm32_bringup.c
的stm32l4_bringup
中。
#ifdef CONFIG_TIMER
ret = stm32l4_timer_initialize ("/dev/timer0", 1);
if (ret != OK)
{
syslog (LOG_ERR, "ERROR: Failed to initialize timer1 at /dev/timer0: %d\n", ret);
}
#endif
编译提示没有定义,果然没有定义。。。全局搜索。
定位在这里:
nuttx/arch/arm/src/chip/stm32l4_tim_lowerhalf.c:441
这部分全部都是灰色的,原来是没有定义定时器。
#if defined(CONFIG_TIMER) && \
(defined(CONFIG_STM32L4_TIM1) || defined(CONFIG_STM32L4_TIM2) || \
defined(CONFIG_STM32L4_TIM3) || defined(CONFIG_STM32L4_TIM4) || \
defined(CONFIG_STM32L4_TIM5) || defined(CONFIG_STM32L4_TIM6) || \
defined(CONFIG_STM32L4_TIM7) || defined(CONFIG_STM32L4_TIM8) || \
defined(CONFIG_STM32L4_TIM15) || defined(CONFIG_STM32L4_TIM16) || \
defined(CONFIG_STM32L4_TIM17))
那就简单了,加上CONFIG_STM32L4_TIM1
的定义就可以了。
然而还是不行,我想哪里有问题呢。。
我想还是这个定义需要出现在config.h
文件中。这个文件是由Kconfig
生成的,那就来修改Kconfig
文件吧。
用Sublime批量写出
if CONFIG_TIMER
config CONFIG_STM32L4_TIM1
bool "Enable TIM1"
default n
config CONFIG_STM32L4_TIM2
bool "Enable TIM2"
default n
config CONFIG_STM32L4_TIM3
bool "Enable TIM3"
default n
config CONFIG_STM32L4_TIM4
bool "Enable TIM4"
default n
config CONFIG_STM32L4_TIM5
bool "Enable TIM5"
default n
config CONFIG_STM32L4_TIM6
bool "Enable TIM6"
default n
config CONFIG_STM32L4_TIM7
bool "Enable TIM7"
default n
config CONFIG_STM32L4_TIM8
bool "Enable TIM8"
default n
config CONFIG_STM32L4_TIM15
bool "Enable TIM15"
default n
config CONFIG_STM32L4_TIM16
bool "Enable TIM16"
default n
config CONFIG_STM32L4_TIM17
bool "Enable TIM17"
default n
endif # CONFIG_TIMER
在make menuconig
中的CONFIG_TIMER
下看看有没有新东西出现。然而還是沒有。思來想去,決定還是在defconfig
文件上做手脚。
将nsh复制一份。重命名为nsh_Clocks_and_Timers
,在这个文件夹下的defconfig
文件末尾天加两行:
CONFIG_TIMER=y
CONFIG_STM32L4_TIM1=y
重新配置:
make distclean
tools/configure.sh b-l475e-iot01a/nsh_Clocks_and_Timers
make menuconfig
检查STM32L4_TIM1
:
看到STM32L4_TIM1 [=y]
了,看起来设置成功了。
现在make
一下。(对了,这里我试了make -j 7
,编译速度大大提升。)
。。。。。。。。。。。。。。。。。。。。。。。
行吧,我承认我实力眼瞎。TIM的开启位置在:
>System Type > STM32L4 Peripheral Support
这里打开TIM2即可。
重新来一遍吧
make distclean
tools/configure.sh b-l475e-iot01a/nsh
make menuconfig
重新开启
> Device Drivers > Timer Driver Support > Timer Support
> Application Configuration > Examples > Timer example
> System Type > STM32L4 Peripheral Support > TIM2
将之前加在stm32l4_bringup
中的代码改成如下:
#if defined(CONFIG_TIMER) && defined(CONFIG_STM32L4_TIM2)
ret = stm32l4_timer_initialize ("/dev/timer0", 2);
if (ret != OK)
{
syslog (LOG_ERR, "ERROR: Failed to initialize TIM2 at /dev/timer0: %d\n", ret);
}
#endif
编译下载。NSH内查找这个定时器
> ls dev
/dev:
console
null
timer0
ttyS0
可以看到timer0已经挂载上去了。
现在运行TIM的例子。
Open /dev/timer0
ERROR: Failed to get timer status: 88
看起来还是有问题。
88这个错误可以查得到。
#define ENOSYS 88
#define ENOSYS_STR "Function not implemented"
功能未实现。
就接下来很长时间内都没有收获,网上也查不到相关信息,最后在NuttX的讨论组上求助,感谢patacongo
的分析(后来查看他的账号,居然是Gregory Nutt
)原因就如信息所示,没有实现。具体代码在:
nuttx\arch\arm\src\stm32l4\stm32l4_tim_lowerhalf.c:124
static const struct timer_ops_s g_timer_ops =
{
.start = stm32l4_start,
.stop = stm32l4_stop,
.getstatus = NULL,
.settimeout = stm32l4_settimeout,
.setcallback = stm32l4_setcallback,
.ioctl = NULL,
};
既没有ioctl
,也没有getstatus
,所以就没办法了么?试着写一个吧。
先确定声明的位置。
nuttx\arch\arm\src\stm32l4\stm32l4_tim_lowerhalf.c:110
/* "Lower half" driver methods **********************************************/
static int stm32l4_start(FAR struct timer_lowerhalf_s *lower);
static int stm32l4_stop(FAR struct timer_lowerhalf_s *lower);
static int stm32l4_settimeout(FAR struct timer_lowerhalf_s *lower, uint32_t timeout);
static void stm32l4_setcallback(FAR struct timer_lowerhalf_s *lower, tccb_t callback, FAR void *arg);
看起来连申明都没有啊,加一个先。
由这里可以确定它的参数:
nuttx\drivers\timers\timer.c:328
ret = lower->ops->getstatus(lower, status);
所以函数的声明应该是这样子的:
static int stm32l4_getstatus(FAR struct timer_lowerhalf_s *lower, FAR struct timer_status_s *status);
刚刚搜索的类似函数找到了一个,在:
nuttx\arch\arm\src\lpc43xx\lpc43_timer.c
static int lpc43_getstatus(FAR struct timer_lowerhalf_s *lower,
FAR struct timer_status_s *status)
{
FAR struct lpc43_lowerhalf_s *priv = (FAR struct lpc43_lowerhalf_s *)lower;
uint32_t elapsed;
tmrinfo("Entry\n");
DEBUGASSERT(priv);
/* Return the status bit */
status->flags = 0;
if (priv->started)
{
status->flags |= TCFLAGS_ACTIVE;
}
if (priv->callback)
{
status->flags |= TCFLAGS_HANDLER;
}
/* Return the actual timeout is milliseconds */
status->timeout = priv->timeout;
/* Get the time remaining until the timer expires (in microseconds) */
/* TODO - check on the +1 in the time left calculation */
elapsed = lpc43_getreg(priv->base + LPC43_TMR_TC_OFFSET);
status->timeleft = ((uint64_t)priv->timeout * elapsed) /
(priv->clkticks + 1);
tmrinfo(" flags : %08x\n", status->flags);
tmrinfo(" timeout : %d\n", status->timeout);
tmrinfo(" timeleft : %d\n", status->timeleft);
return OK;
}
首先将lpc43_lowerhalf_s
换成stm32l4_lowerhalf_s
。
然后stm32l4_lowerhalf_s
成员中并没有timeout
,这里有两种方法。
1. 笨办法。写代码获得。
设定timeout
的函数中有设定方法:
maxtimeout = (1 << priv->resolution) - 1;
if (timeout > maxtimeout)
{
uint64_t freq = (maxtimeout * 1000000) / timeout;
STM32L4_TIM_SETCLOCK(priv->tim, freq);
STM32L4_TIM_SETPERIOD(priv->tim, maxtimeout);
}
else
{
STM32L4_TIM_SETCLOCK(priv->tim, 1000000);
STM32L4_TIM_SETPERIOD(priv->tim, timeout);
}
将其过来写即可得到timeout。
先写出缺失的STM32L4_TIM_GETCLOCK
,首先找到STM32L4_TIM_SETCLOCK
。
nuttx\arch\arm\src\chip\stm32l4_tim.h:60:
#define STM32L4_TIM_SETCLOCK(d,freq) ((d)->ops->setclock(d,freq))
照着写一个get就行了。
#define STM32L4_TIM_GETCLOCK(d) ((d)->ops->getclock(d))
接下来,寻找ops->setclock
,这个是在文件后面的结构体stm32l4_tim_ops_s
中出现了。在里面加上:
uint32_t (*getclock)(FAR struct stm32l4_tim_dev_s *dev);
这个是只是定义而已。
现在该写定义了。转到:
nuttx\arch\arm\src\chip\stm32l4_tim.c
在前面声明
static uint32_t stm32l4_tim_getclock(FAR struct stm32l4_tim_dev_s *dev);
在stm32l4_tim_ops
中加上新的部分。
.getclock = stm32l4_tim_getclock,
该写内容了,思路就是反向写stm32l4_tim_setclock
。
首先定义定时器输入频率和分频数。
uint32_t freqin;
uint16_t prescaler;
接下来赋值freqin
switch (((struct stm32l4_tim_priv_s *)dev)->base)
{
#ifdef CONFIG_STM32L4_TIM1
case STM32L4_TIM1_BASE:
freqin = BOARD_TIM1_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM2
case STM32L4_TIM2_BASE:
freqin = BOARD_TIM2_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM3
case STM32L4_TIM3_BASE:
freqin = BOARD_TIM3_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM4
case STM32L4_TIM4_BASE:
freqin = BOARD_TIM4_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM5
case STM32L4_TIM5_BASE:
freqin = BOARD_TIM5_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM6
case STM32L4_TIM6_BASE:
freqin = BOARD_TIM6_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM7
case STM32L4_TIM7_BASE:
freqin = BOARD_TIM7_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM8
case STM32L4_TIM8_BASE:
freqin = BOARD_TIM8_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM15
case STM32L4_TIM15_BASE:
freqin = BOARD_TIM15_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM16
case STM32L4_TIM16_BASE:
freqin = BOARD_TIM16_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM17
case STM32L4_TIM17_BASE:
freqin = BOARD_TIM17_FREQUENCY;
break;
#endif
default:
return -EINVAL;
}
接下来,setter里面剩下的内容:
/* Select a pre-scaler value for this timer using the input clock
* frequency.
*/
prescaler = freqin / freq;
/* We need to decrement value for '1', but only, if that will not to
* cause underflow.
*/
if (prescaler > 0)
{
prescaler--;
}
/* Check for overflow as well. */
if (prescaler > 0xffff)
{
prescaler = 0xffff;
}
stm32l4_putreg16(dev, STM32L4_BTIM_PSC_OFFSET, prescaler);
stm32l4_tim_enable(dev);
return prescaler;
最后将分频数写入的寄存器,直接读取就可以得到分频数。有put,那么一定有get。
在下面找到了stm32l4_getreg16
,所以就可以这么写:
prescaler = stm32l4_getreg16(dev,STM32L4_BTIM_PSC_OFFSET);
setter里倒着看,写入前检查了是否溢出,那么读取后就不需要检查溢出了。再往前分频数自减,这个应该和寄存器配置是从00开始有关。看看手册。在1179页,有说明。
那么就有:
clock = BOARD_TIM2_FREQUENCY / (stm32l4_getreg16(dev,STM32L4_BTIM_PSC_OFFSET) + 1);
这部分就写完了。
整体内容如下:
/************************************************************************************
* Name: stm32l4_tim_getclock
************************************************************************************/
static uint32_t stm32l4_tim_getclock(FAR struct stm32l4_tim_dev_s *dev)
{
uint32_t freqin;
uint32_t clock;
DEBUGASSERT(dev != NULL);
/* Get the input clock frequency for this timer. These vary with
* different timer clock sources, MCU-specific timer configuration, and
* board-specific clock configuration. The correct input clock frequency
* must be defined in the board.h header file.
*/
switch (((struct stm32l4_tim_priv_s *)dev)->base)
{
#ifdef CONFIG_STM32L4_TIM1
case STM32L4_TIM1_BASE:
freqin = BOARD_TIM1_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM2
case STM32L4_TIM2_BASE:
freqin = BOARD_TIM2_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM3
case STM32L4_TIM3_BASE:
freqin = BOARD_TIM3_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM4
case STM32L4_TIM4_BASE:
freqin = BOARD_TIM4_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM5
case STM32L4_TIM5_BASE:
freqin = BOARD_TIM5_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM6
case STM32L4_TIM6_BASE:
freqin = BOARD_TIM6_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM7
case STM32L4_TIM7_BASE:
freqin = BOARD_TIM7_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM8
case STM32L4_TIM8_BASE:
freqin = BOARD_TIM8_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM15
case STM32L4_TIM15_BASE:
freqin = BOARD_TIM15_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM16
case STM32L4_TIM16_BASE:
freqin = BOARD_TIM16_FREQUENCY;
break;
#endif
#ifdef CONFIG_STM32L4_TIM17
case STM32L4_TIM17_BASE:
freqin = BOARD_TIM17_FREQUENCY;
break;
#endif
default:
return -EINVAL;
}
clock = freqin / (stm32l4_getreg16(dev,STM32L4_BTIM_PSC_OFFSET) + 1);
return clock;
}
现在,lowerhalf
里就可以写;
uint32_t clock = STM32L4_TIM_GETCLOCK(priv->tim);
下面写STM32L4_TIM_GETPERIOD
照着上面的写法,则可以写出:
nuttx\arch\arm\src\chip\stm32l4_tim.c
static uint32_t stm32l4_tim_getperiod(FAR struct stm32l4_tim_dev_s *dev);
...
static const struct stm32l4_tim_ops_s stm32l4_tim_ops =
{
...
.getperiod = stm32l4_tim_getperiod,
...
};
...
static uint32_t stm32l4_tim_getperiod(FAR struct stm32l4_tim_dev_s *dev)
{
DEBUGASSERT(dev != NULL);
return stm32l4_getreg32(dev, STM32L4_BTIM_ARR_OFFSET);
}
和
nuttx\arch\arm\src\chip\stm32l4_tim.h
#define STM32L4_TIM_GETPERIOD(d) ((d)->ops->getperiod(d))
...
struct stm32l4_tim_ops_s
{
...
uint32_t (*getperiod)(FAR struct stm32l4_tim_dev_s *dev);
...
};
现在,lowerhalf
里就可以写:
uint32_t period = STM32L4_TIM_GETPERIOD(priv->tim);
按照stm32l4_settimeout
后面的可以写出:
if (clock == 1000000)
{
timeout = period;
}
else
{
timeout = (maxtimeout * 1000000) / clock;
}
status->timeout = timeout;
status就差一个timeleft
了。
思路大概是这样,读取CNT和PSC,计算得出剩余时间。
计数器有向上和向下两种计数方式,但是在289行启动时,设定了向上计数法,所以,不用再做判断。
考虑到CNT不断的在累计,所以越晚读取越好(虽然也不会差多少就是了)。
PSC这里不用再读取了,因为CNT的计数频率就是stm32l4_tim_getclock
返回的值。
向上计数法中,CNT从0开始,当等于ARR中值的时候,溢出。
有些定时器没有32位的定时器。正当我要做分支的时候,想起来前面还没做分支,检查了一下,发现这个:
maxtimeout = (1 << priv->resolution) - 1;
而这个priv->resolution
就是计时器的位数。
那么就好写了。maxtimeout - STM32L4_TIM_GETCOUNTER(priv->tim)
就是CNT剩余时间。按照clock
的两种情况,可以得出:
uint32_t clock_factor = (clock == 1000000)? 1: (clock / 1000000);
status->timeleft = (timeout - STM32L4_TIM_GETCOUNTER(priv->tim)) * clock_factor;
剩下的照搬即可,整体代码如下:
static int stm32l4_getstatus (FAR struct timer_lowerhalf_s *lower, FAR struct timer_status_s *status)
{
FAR struct stm32l4_lowerhalf_s *priv = (FAR struct stm32l4_lowerhalf_s *) lower;
uint64_t maxtimeout;
uint32_t timeout;
DEBUGASSERT(priv);
/* Return the status bit */
status->flags = 0;
if (priv->started)
{
status->flags |= TCFLAGS_ACTIVE;
}
if (priv->callback)
{
status->flags |= TCFLAGS_HANDLER;
}
// Get timeout
maxtimeout = (1 << priv->resolution) - 1;
uint32_t clock = STM32L4_TIM_GETCLOCK(priv->tim);
uint32_t period = STM32L4_TIM_GETPERIOD(priv->tim);
if (clock == 1000000)
{
timeout = period;
}
else
{
timeout = (maxtimeout * 1000000) / clock;
}
status->timeout = timeout;
/* Get the time remaining until the timer expires (in microseconds) */
uint32_t clock_factor = (clock == 1000000)? 1: (clock / 1000000);
status->timeleft = (timeout - STM32L4_TIM_GETCOUNTER(priv->tim)) * clock_factor;
return OK;
}
这样就可以了,吧。
改一下前面的g_timer_ops
函数。
// .getstatus = NULL,
.getstatus = stm32l4_getstatus,
编译下载运行timer
nsh> timer
Open /dev/timer0
flags: 00000000 timeout: -1 timeleft: 4154504656 nsignals: 0
Set timer interval to 1000000
flags: 00000000 timeout: 16960 timeleft: 999992 nsignals: 0
Attach timer handler
flags: 00000002 timeout: 16960 timeleft: 998924 nsignals: 0
Start the timer
flags: 00000003 timeout: 16960 timeleft: 791364 nsignals: 1
flags: 00000003 timeout: 16960 timeleft: 571364 nsignals: 1
flags: 00000003 timeout: 16960 timeleft: 351364 nsignals: 1
flags: 00000003 timeout: 16960 timeleft: 131364 nsignals: 1
flags: 00000003 timeout: 16960 timeleft: 999896 nsignals: 2
flags: 00000003 timeout: 16960 timeleft: 791365 nsignals: 2
flags: 00000003 timeout: 16960 timeleft: 571365 nsignals: 2
flags: 00000003 timeout: 16960 timeleft: 351365 nsignals: 2
flags: 00000003 timeout: 16960 timeleft: 131365 nsignals: 2
flags: 00000003 timeout: 16960 timeleft: 999896 nsignals: 3
flags: 00000003 timeout: 16960 timeleft: 791366 nsignals: 3
flags: 00000003 timeout: 16960 timeleft: 571366 nsignals: 3
flags: 00000003 timeout: 16960 timeleft: 351366 nsignals: 3
flags: 00000003 timeout: 16960 timeleft: 131366 nsignals: 3
flags: 00000003 timeout: 16960 timeleft: 999896 nsignals: 4
flags: 00000003 timeout: 16960 timeleft: 791367 nsignals: 4
flags: 00000003 timeout: 16960 timeleft: 571367 nsignals: 4
flags: 00000003 timeout: 16960 timeleft: 351367 nsignals: 4
flags: 00000003 timeout: 16960 timeleft: 131367 nsignals: 4
flags: 00000003 timeout: 16960 timeleft: 999896 nsignals: 5
Stop the timer
flags: 00000002 timeout: 16960 timeleft: 1000000 nsignals: 6
Finished
看起来是哪里的运算出问题了。
调整再三,问题出现在了uint32_t
和uint16_t
的转换上,明显是一个uint32赋值给了uint16。加了很多printf,可以确定写入TIM2的ARR寄存器的是一个32位的,但是读出来的是一个16位的,寄存器地址无误。怎么都没发现我的代码哪里有问题。
再三确认我写的代码无误后,放松了一会。。。。。。。。。。。
我换了个思路,装进去的值是不是出问题了呢?于是去查找setperiod
的相关代码。结果还真发现了问题。
struct stm32l4_tim_ops_s
{
...
void (*setperiod)(FAR struct stm32l4_tim_dev_s *dev, uint16_t period);
...
}
这里的定义不知道什么时候变成了16位的,直接导致装入数据缩水。
之后就正常了。
nsh> timer
Open /dev/timer0
flags: 00000000 timeout: 1607101170 timeleft: 4154504656 nsignals: 0
Set timer interval to 1000000
flags: 00000000 timeout: 1000000 timeleft: 999992 nsignals: 0
Attach timer handler
flags: 00000002 timeout: 1000000 timeleft: 998924 nsignals: 0
Start the timer
flags: 00000003 timeout: 1000000 timeleft: 791364 nsignals: 1
flags: 00000003 timeout: 1000000 timeleft: 571364 nsignals: 1
flags: 00000003 timeout: 1000000 timeleft: 351364 nsignals: 1
flags: 00000003 timeout: 1000000 timeleft: 131364 nsignals: 1
flags: 00000003 timeout: 1000000 timeleft: 999896 nsignals: 2
flags: 00000003 timeout: 1000000 timeleft: 791365 nsignals: 2
flags: 00000003 timeout: 1000000 timeleft: 571365 nsignals: 2
flags: 00000003 timeout: 1000000 timeleft: 351365 nsignals: 2
flags: 00000003 timeout: 1000000 timeleft: 131365 nsignals: 2
flags: 00000003 timeout: 1000000 timeleft: 999896 nsignals: 3
flags: 00000003 timeout: 1000000 timeleft: 791366 nsignals: 3
flags: 00000003 timeout: 1000000 timeleft: 571366 nsignals: 3
flags: 00000003 timeout: 1000000 timeleft: 351366 nsignals: 3
flags: 00000003 timeout: 1000000 timeleft: 131366 nsignals: 3
flags: 00000003 timeout: 1000000 timeleft: 999896 nsignals: 4
flags: 00000003 timeout: 1000000 timeleft: 791367 nsignals: 4
flags: 00000003 timeout: 1000000 timeleft: 571367 nsignals: 4
flags: 00000003 timeout: 1000000 timeleft: 351367 nsignals: 4
flags: 00000003 timeout: 1000000 timeleft: 131367 nsignals: 4
flags: 00000003 timeout: 1000000 timeleft: 999896 nsignals: 5
Stop the timer
flags: 00000002 timeout: 1000000 timeleft: 1000000 nsignals: 6
Finished
成功运行。
上一篇: servlet
下一篇: PHP 八种基本的数据类型小结