Nasm Assembly Linux Timer or Sleep

nasm assembly linux timer or sleep

There is a system call for sleeping the program, sys_nanosleep:

 sys_nanosleep : eax = 162, ebx = struct timespec *, ecx = struct timespec *

this struct timespec structure has two members:

 ;; This is for 32-bit.  Note that x86-64 uses 2x 64-bit members
tv_sec ; 32 bit seconds
tv_nsec ; 32 bit nanoseconds

this structure can be declared in nasm as:

section .data

timeval:
tv_sec dd 0
tv_usec dd 0

and then you sets the values and call it as:

mov dword [tv_sec], 5
mov dword [tv_usec], 0
mov eax, 162
mov ebx, timeval
mov ecx, 0
int 0x80

the program then will sleep for 5 seconds. A complete example:

global  _start

section .text
_start:

; print "Sleep"
mov eax, 4
mov ebx, 1
mov ecx, bmessage
mov edx, bmessagel
int 0x80

; Sleep for 5 seconds and 0 nanoseconds
mov dword [tv_sec], 5
mov dword [tv_usec], 0
mov eax, 162
mov ebx, timeval
mov ecx, 0
int 0x80

; print "Continue"
mov eax, 4
mov ebx, 1
mov ecx, emessage
mov edx, emessagel
int 0x80

; exit
mov eax, 1
mov ebx, 0
int 0x80

section .data

timeval:
tv_sec dd 0
tv_usec dd 0

bmessage db "Sleep", 10, 0
bmessagel equ $ - bmessage

emessage db "Continue", 10, 0
emessagel equ $ - emessage

Sleep for x milliseconds in 16 bit bare metal nasm assembly

One day, I too needed a delay routine capable of doing delays ranging from 0.5 sec to just a few msec. Read all about it in this CodeReview question, and especially the reason why I needed to take this approach.

My solution was to find out how many iterations a delay routine can do in the interval between 2 ticks of the standard 18.2Hz timer. Those ticks are 55 msec apart. Because sometimes measurements can be erratic I only accepted the results if 2 consecutive measurements varied by less than 1%%. Finally I divided the good measurement by 55 to obtain the number of iterations per msec aka SpeedFactor. Hereafter, whenever I wanted to pause the program I multiplied the desired delay expressed in msec by this SpeedFactor and then performed that number of iterations within the delay routine.

The full code:

[bits 16]
[org 0x7C00]

xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
cld

; Measure the number of iterations (within the ShortWait routine) per msec
; Only accept if consecutive measurements vary by less than 1%%
; If measurements remain erratic than do accept the last one
mov bp, 10 ; Max try
call GetSpeedFactor ; -> DX:AX
.a: xchg si, ax ; 'mov si, ax'
mov di, dx
call GetSpeedFactor ; -> DX:AX
push ax dx ; (1)
.b: sub ax, si
sbb dx, di
jnb .c
add ax, si
adc dx, di
xchg si, ax
xchg di, dx
jmp .b
.c: mov cx, 1000
xchg ax, cx
mul dx
xchg ax, cx
mov dx, 1000
mul dx
add dx, cx
sub si, ax
sbb di, dx
pop dx ax ;(1)
cmc
dec bp
jnbe .a
mov [SpeedFactor], ax
mov [SpeedFactor+2], dx

mov si, msg
lodsb
More: mov bx, 0x0007 ; BH DisplayPage 0, BL GraphicsColor 7
mov ah, 0x0E ; BIOS.Teletype
int 10h
mov bx, 300 ; 0.3 sec
call Pause
lodsb
cmp al, 0
jne More

cli
hlt
jmps $-2

msg db "The quick brown fox jumps over the lazy dog.", 0
SpeedFactor dd 0
; ----------------------------------------------
; IN () OUT (dx:ax)
; Wait for the start of a new TimerTick period (54.9254 msec)
; Then measure a 4 tick period (219.7016 msec)
GetSpeedFactor: push bx cx
mov bx, 1
call .ShortWait ; -> DX:AX BX=0
mov bl, 4 ; BH=0
call .ShortWait ; -> DX:AX BX=0
mov cx, 10
xchg ax, cx
mul dx
xchg ax, cx
mov dx, 10
mul dx
add dx, cx
mov cx, 2197
xchg ax, bx ; BX=0
xchg dx, ax
div cx
xchg ax, bx
div cx
mov dx, bx
pop cx bx
ret
; - - - - - - - - - - - - - - - - - - - - - - -
.ShortWait: mov ax, -1
cwd
; --- --- --- --- --- --- --- ---
; IN (dx:ax,bx) OUT (dx:ax,bx)
; Do DX:AX iterations or loop until Timer did BX Ticks
ShortWait: push ds cx si di
xchg si, ax ; 'mov si, ax'
mov di, dx
xor ax, ax
cwd
mov ds, ax
.a: mov cx, [046Ch] ; BIOS Timer
.b: sub si, 1
sbb di, 0
jb .c
add ax, 1
adc dx, 0
cmp cx, [046Ch]
je .b
dec bx
jnz .a
.c: pop di si cx ds
ret
; ----------------------------------------------
; IN (bx) OUT ()
Pause: push ax bx dx
mov ax, [SpeedFactor+2]
mul bx
xchg bx, ax
mul word [SpeedFactor]
add dx, bx
mov bx, -1
call ShortWait ; -> DX:AX BX
pop dx bx ax
ret
; ----------------------------------------------

times 510-($-$$) db 0
dw 0xAA55

The code assembles with FASM. For NASM, you will need to change code like

push ax bx dx
...
pop dx bx ax

into

push ax
push bx
push dx
...
pop dx
pop bx
pop ax

How to implement usleep in x86_64 asm?

I've just started learning x86_64 asm and I would like to implement a usleep like procedure without using any syscalls.

Without using any system calls; the only viable option would be a busy loop relying on the timestamp from either the rdtsc or rdtscp instruction.

This involves converting the delay from microseconds into whatever the CPU's TSC frequency is (which needs to be determined somehow, possibly by measuring it with some other time source), in addition to avoiding various pitfalls (e.g. time stamp being different on different CPUs); and these things make it "not easy".

The other problem is that for a CPU running at several GHz each microsecond represents thousands of wasted clock cycles that the CPU could've spent doing useful work/running a different task, or even just doing nothing efficiently (by switching the CPU into a power saving state until a timer IRQ occurs). This is why a system call is better - the kernel is the only thing that has the privilege needed to implement time delays efficiently.

How to set 1 second time delay at assembly language 8086

What i finally ended up using was the nop loop

; start delay

mov bp, 43690
mov si, 43690
delay2:
dec bp
nop
jnz delay2
dec si
cmp si,0
jnz delay2
; end delay

I used two registers which I set them both to any high value
and its gonna keep on looping until both values go to zero

What I used here was AAAA for both SI and BP, i ended up with roughly 1 second for each delay loop.

Thanks for the help guys, and yes, we still use MS DOS for this assembly language course :(

Linux periodic C timers without using signal callback

how can I differentiate in the SIG-handler, that this signal is for my timer and not other events ?

Check out the sigevent(7) man page linked from timer_create(2). One of the members of the struct sigevent that you pass to timer_create is union sigval sigev_value. This union isn't defined in the man page, but POSIX explains that it's simply

union sigval {
int sival_int; // integer signal value
void* sival_ptr; // pointer signal value
};

Whatever you set here will be passed to your signal handler as the si_value member of its siginfo_t * second argument, provided you use SA_SIGINFO when calling sigaction. So you just need to use different values here as you set up timers corresponding to different callbacks. You could use sival_int for an integer ID of your own choosing that uniquely identifies this particular timer from all others, or sival_ptr for a pointer to a function or some more elaborate data structure that tells you how to handle the timer tick. Then your signal handler just needs to inspect this argument and dispatch to the callback it specifies.

You might also consider the SIGEV_THREAD mode of timer_create, which fires off a new thread with the handler instead of raising a signal. So if you want your callback to run in its own thread, that could be a simpler route to take, as you don't need the signal handler to act as dispatcher.

But if you don't want additional threads, I don't think there is any way to avoid working with signals. They're about the only mechanism that Unix provides for running code asynchronously.

Do be mindful of the many restrictions on what can be done from within a signal handler; in particular, practically the entire standard C library is off limits. As such, your "asynchronous" callbacks may not be able to do much except set a flag to tell your main event loop to do the real work at some later time. So you may not gain much over a synchronous poll-type model anyway.

Implementing a low-overhead interval timer with C++ in Linux

Read time(7), signal(7), timerfd_create(2), poll(2), nanosleep(2) and Advanced Linux Programming.

Your signal handler is incorrect (it should not call printf; it could write).

You could have

while(1) poll(NULL, 0, 1);

but probably a real event loop using poll on a file descriptor initialized with timerfd_create should be better.

I assume of course that you are fairly confident that every periodic task lasts much less than the period. (e.g. that each task needs no more than 50 milliseconds but has a 100 millisecond period).

How can I send a signal every day without crontab?

I don't know other way to create asynchronous behaviors on Linux

Linux itself seems not to support anything that is similar to what you want.

To perform certain actions at a certain time, some program must be started and run in the background until the action shall be performed. If the action shall be performed cyclically, the program must be running permanently.

Using a crontab has the advantage that only one program (cron) is running in the background even if you have hundreds of different actions in your crontab. However, one program (cron) is running in the background permanently.

The same is true for systemd.

If you don't want to use such a tool, your program must run in the background permanently.

timer_create

This can be used if you require a quite high precision (for example less than one second).

If you don't need a high precision and you don't want cron or similar, I would do something like this:

seconds_per_day = 60*60*24;
next_time = time(NULL) + seconds_per_day;
while(1)
{
usleep(5000000);
if(time(NULL) >= next_time)
{
perform_action();
next_time += seconds_per_day;
}
}

In the example I use usleep() to wait for 5 seconds. Using a longer time (e.g. 10 seconds) will reduce the CPU power consumed by your program running in the background - and make the exact point in time when you trigger your action more imprecise.

The example simply triggers one action every 24h.

However, you can use the same principle to trigger some action at a certain time (e.g. 11:30pm) or multiple actions at different times...



Related Topics



Leave a reply



Submit