क्या विशेषताएं अन्य प्रकार के ओएस से वास्तविक समय को अलग करती हैं?


16

मैं एक छोटे से तथाकथित वास्तविक समय कर्नेल के साथ प्रयोग कर रहा हूं जो मूल रूप से अगले प्रधानमंत्री की गिनती के अलावा कुछ नहीं कर सकता। यह बाधित-संचालित I / O का उपयोग करता है। लेकिन यह एक वास्तविक समय कर्नेल क्यों है?

मैंने पढ़ा कि लिनक्स 2002 में एक वास्तविक समय का कर्नेल बन गया, क्या यह सही है?

मैं Altera DE2 का उपयोग करता हूं और जिस कोड को मैं इसे आधार बना रहा हूं वह है 1 असेंबली फाइल, 1 हेडर फाइल और 2 सी फाइलें। कृपया मुझे समझने में मदद करें।

# Uart_0 at 0x860

.equ de2_uart_0_base,0x860

# Timer_1 at 0x920, interrupt index 10 (mask 2^10 = 0x400)

.equ de2_timer_1_base,0x920
.equ de2_timer_1_intmask,0x400

# Timeout value for 0,1 ms tick-count interval (CHANGED in every version)

.equ de2_timer_1_timeout_value,4999

# Required tick count per time-slice, meaning
# the number of timer-interrupts before a thread-switch is performed

.equ oslab_ticks_per_timeslice,100

# Interrupt address at 0x800020

.equ de2_nios2_interrupt_address,0x800020

#
# End of device-address definitions
#
################################################################

################################################################
#
# Definition of variables for keeping system time etcetera.
#

.data
.align 2
.global oslab_internal_globaltime
oslab_internal_globaltime:  .word 0

# Definition of variable for remembering the number of
# timer-interrupts since the last thread-switch

.data
.align 2
.global oslab_internal_tickcount
oslab_internal_tickcount:   .word 0

# Definition of system (interrupt) stack, sp, and gp

.data
.align 2
oslab_internal_gp:  .word 0
oslab_internal_sp:  .word 0
oslab_system_stack: .fill 256,1,0
oslab_system_stacktop:

# Definition of the end-of-timeslice message.

oslab_internal_yield_message:
                    .asciz "\n#### Thread yielded after using %d tick%c."

#
# End of system-time variable definitions.
#
################################################################

################################################################
#
# Interrupt handling code.
#

# Stub for interrupt handler

.text
oslab_internal_stub:
    movia   et,oslab_exception_handler
    jmp     et

# The interrupt handler

oslab_exception_handler:
    # Check source of exception, following the procedure
    # described in the Nios II Processor Reference Handbook.

    rdctl   et,estatus      # Check ESTATUS
    andi    et,et,1         # Test EPIE
    beq     et,r0,oslab_exception_was_not_an_interrupt
    rdctl   et,ipending     # Check IPENDING
    beq     et,r0,oslab_exception_was_not_an_interrupt

    # If control comes here, we have established that the
    # exception was caused by an interrupt.
    # Subtract 4 from ea, so that the interrupted instruction
    # will be re-run when we return.

    subi    ea,ea,4

    # Check the source of the interrupt.
    # Possible source No. 1: Timer_1 (currently the only source).

    rdctl   et,ipending
    andi    et,et,de2_timer_1_intmask
    bne     et,r0,oslab_timer_1_interrupt

    # If control comes here, we have an interrupt from an unknown source.
    # This condition is IGNORED in this version of OSLAB.

    eret

oslab_exception_was_not_an_interrupt:

    # Test if the interrupted instruction was a TRAP

    subi    sp,sp,4         # PUSH r8 (instruction 1)
    stw     r8,0(sp)        # PUSH r8 (instruction 2)

    movia   r8,0x003b683a   # binary code for TRAP
    ldw     et,-4(ea)       # Load interrupted instruction
    cmpeq   et,et,r8        # Compare to binary code for TRAP

    # Result from comparison is now in et.

    ldw     r8,0(sp)        # POP r8 (instruction 1)
    addi    sp,sp,4         # POP r8 (instruction 2)

    # Use the comparison result in et as branch condition.
    # The value in et will also be used later, to tell if the
    # exception was a trap or an interrupt.

    bne     et,r0,oslab_trap_handler

    # If control comes here, we have an exception which was not a TRAP.
    # This should not normally happen.
    # However, someone writing programs for the OSLAB micro-operating system
    # could perhaps use unimplemented instructions. To catch unimplemented
    # instructions, we insert a BREAK instruction here. This will stop execution
    # unless the program is run through the debugger.

    break 0
    eret

oslab_timer_1_interrupt:

    # Acknowledge the timer_1 interrupt.

    movia   et,de2_timer_1_base
    stw     r0,0(et)

    # Save contents of R8, to get a free register for
    # temporary values.

    subi    sp,sp,4
    stw     r8,0(sp)        # PUSH r8

    # Increase system clock.

    movia   r8,oslab_internal_globaltime
    ldw     et,0(r8)
    addi    et,et,1
    stw     et,0(r8)

    # Increase tick counter.

    movia   r8,oslab_internal_tickcount
    ldw     et,0(r8)
    addi    et,et,1
    stw     et,0(r8)

    # Restore original contents of R8.

    ldw     r8,0(sp)        # POP r8
    addi    sp,sp,4

    # Check value of tick counter,
    # against the required number of ticks per time-slice.
    # Note: oslab_ticks_per_timeslice is an assembler constant,
    # and not a variable. Hence, no load/store-instructions here.

    subi    et,et,oslab_ticks_per_timeslice

    # If the result from the subtraction is zero (or perhaps positive),
    # then it is time to switch threads.

    bge     et,r0,oslab_time_to_switch

    # If we fall-through here, then we have had one of those many
    # timer interrupts on which we should not switch threads.
    # Return to caller.

    eret

oslab_time_to_switch:

    # This code will now fall-through into the TRAP handler
    # which performs a context switch.
    #
    # We will print out a message for each timer interrupt.
    # To be able to tell that we had a timer interrupt, and not
    # a TRAP, we set et to zero.

    movi    et,0

oslab_trap_handler:

    # Save registers r1 through r23, plus fp, gp, ra and ea

    .set noat               # R1 is used here.
    subi    sp,sp,108       # Make room for all registers. 
    stw     r1, 4(sp)       # R1 is saved in slot 1, not slot 0.
    stw     r2, 8(sp)
    stw     r3,12(sp)
    stw     r4,16(sp)
    stw     r5,20(sp)
    stw     r6,24(sp)
    stw     r7,28(sp)
    stw     r8,32(sp)
    stw     r9,36(sp)
    stw    r10,40(sp)
    stw    r11,44(sp)
    stw    r12,48(sp)
    stw    r13,52(sp)
    stw    r14,56(sp)
    stw    r15,60(sp)
    stw    r16,64(sp)
    stw    r17,68(sp)
    stw    r18,72(sp)
    stw    r19,76(sp)
    stw    r20,80(sp)
    stw    r21,84(sp)
    stw    r22,88(sp)
    stw    r23,92(sp)
    stw    r26,96(sp)
    stw    r28,100(sp)
    stw    r31,104(sp)
    stw     ea,0(sp)        # Special case, saved in slot 0.

    mov     r4,sp           # Copy stack pointer to param1 register
    movia   sp,oslab_system_stacktop     # Use system stack instead

    # Test et to see if this was a timeout event or a TRAP.

    beq     et,r0,oslab_not_a_trap

    # If this was a trap event, we fall through here.
    # Our simplified printf is used to print a message,
    # saying that the previous thread yielded parts of its time-slice.

################################################################
#
#   The following code prints a nice message. Nothing more.
#   This code saves and restores all registers it uses.
#   You can safely ignore the following code, up to
#   (but NOT including) the label oslab_not_a_trap.
#
    subi    sp,sp,4         # Contents of r4 must be preserved.
    stw     r4,0(sp)        # PUSH r4.

    movia   r4,oslab_internal_yield_message
    movia   r5,oslab_internal_tickcount
    ldw     r5,0(r5)
    movi    r6,0            # Gold-plating: check if 1 tick or several ticks.
    subi    et,r5,1         # Do not print the s if only 1 tick.
    beq     et,r0,oslab_no_plural_ticks
    movi    r6,'s'          # If 0 ticks, or 2 or more ticks, print the s.
oslab_no_plural_ticks:
    call    printf

    ldw     r4,0(sp)        # POP r4
    addi    sp,sp,4
#
#   This comment marks the end of the code for printing a nice message.
#   Now comes other code, which is potentially much more interesting.
#
################################################################

    # Move on to thread-switch code.

oslab_not_a_trap:

    # Clear tick counter, since we are going to switch threads.

    movia   et,oslab_internal_tickcount
    stw     r0,0(et)

    # Now it is time to execute the thread-switch code.
    # We use the more general callr, rather than call.

    movia   et,oslab_internal_threadswitch
    callr   et              # Call thread switch routine written in C

    mov     sp,r2           # Copy return value to stack pointer
                            # Yes, the system stack pointer is lost,
                            # but who cares? We will not need it any more.

    # restore registers
    ldw     r1, 4(sp)
    ldw     r2, 8(sp)
    ldw     r3,12(sp)
    ldw     r4,16(sp)
    ldw     r5,20(sp)
    ldw     r6,24(sp)
    ldw     r7,28(sp)
    ldw     r8,32(sp)
    ldw     r9,36(sp)
    ldw    r10,40(sp)
    ldw    r11,44(sp)
    ldw    r12,48(sp)
    ldw    r13,52(sp)
    ldw    r14,56(sp)
    ldw    r15,60(sp)
    ldw    r16,64(sp)
    ldw    r17,68(sp)
    ldw    r18,72(sp)
    ldw    r19,76(sp)
    ldw    r20,80(sp)
    ldw    r21,84(sp)
    ldw    r22,88(sp)
    ldw    r23,92(sp)
    ldw    r26,96(sp)
    ldw    r28,100(sp)
    ldw    r31,104(sp)
    ldw     ea,0(sp)        # Special case
    addi    sp,sp,108

    eret                    # Return from exception

#
# End of exception handling code.
#
################################################################

################################################################
#
# Startup code.
#
# When the system is started, Altera-supplied code initializes the
# Nios II CPU and cache memories, and then calls alt_main.
#

.global alt_main
alt_main:
    wrctl   status,r0       # Disable interrupts.
    wrctl   ienable,r0      # Clear all bits in IENABLE.

    # Now copy the stub.

    movia   r8,oslab_internal_stub
    movia   r9,de2_nios2_interrupt_address
    ldw     r10,0(r8)
    stw     r10,0(r9)
    ldw     r10,4(r8)
    stw     r10,4(r9)
    ldw     r10,8(r8)
    stw     r10,8(r9)

    # Initialize timer_1.

    movia   r8,de2_timer_1_base
    movia   r9,de2_timer_1_timeout_value
    srli    r10,r9,16
    stw     r10,12(r8)      # Write periodh
    andi    r10,r9,0xffff
    stw     r10,8(r8)       # Write periodl
    movi    r10,7           # Continuous, interrupt on timeout, and start
    stw     r10,4(r8)

    # Initialize CPU for interrupts from timer_1.

    movi    r10,de2_timer_1_intmask
    wrctl   ienable,r10
    movi    r10,1
    wrctl   status,r10

    # Call to main. Do not jump, main is a subroutine,
    # and may execute a ret instruction.

    subi    sp,sp,4
    stw     ra,0(sp)        # PUSH r31
    movia   r8,main
    callr   r8
    ldw     ra,0(sp)        # POP r31
    addi    sp,sp,4

    # If main returns, we will return directly to the routine
    # that called us (that called alt_main).

    ret

#
# End of startup code.
#
################################################################

################################################################
#
# Helper functions for initialization and thread handling.
#

.text
.align 2
.global oslab_internal_get_gp
oslab_internal_get_gp:
    mov     r2,gp
    ret

.global oslab_begin_critical_region
oslab_begin_critical_region:
    wrctl   status,r0
    ret

.global oslab_end_critical_region
oslab_end_critical_region:
    movi    r8,1
    wrctl   status,r8
    ret

.global oslab_get_internal_globaltime
oslab_get_internal_globaltime:
    movia   r2,oslab_internal_globaltime
    ldw     r2,0(r2)
    ret

.global oslab_get_internal_tickcount
oslab_get_internal_tickcount:
    movia   r2,oslab_internal_tickcount
    ldw     r2,0(r2)
    ret

.global oslab_yield
oslab_yield:
    trap
    ret

#
# End of helper functions.
#
################################################################
#
# ********************************************************
# *** You don't have to study the code below this line ***
# ********************************************************
#
################################################################
#
# A simplified printf() replacement.
# Implements the following conversions: %c, %d, %s and %x.
# No format-width specifications are allowed,
# for example "%08x" is not implemented.
# Up to four arguments are accepted, i.e. the format string
# and three more. Any extra arguments are silently ignored.
#
# The printf() replacement relies on routines
# out_char_uart_0, out_hex_uart_0,
# out_number_uart_0 and out_string_uart_0
# in file oslab_lowlevel_c.c
#
# We need the macros PUSH and POP - definitions follow.

# PUSH reg - push a single register on the stack

.macro PUSH reg
    subi sp,sp,4    # reserve space on stack
    stw  \reg,0(sp) # store register
.endm

# POP  reg - pop a single register from the stack

.macro POP  reg
    ldw  \reg,0(sp) # fetch top of stack contents
    addi sp,sp,4    # return previously reserved space
.endm

.text
.global printf
printf:
    PUSH    ra      # PUSH return address register r31.
    PUSH    r16     # R16 will point into format string.
    PUSH    r17     # R17 will contain the argument number.
    PUSH    r18     # R18 will contain a copy of r5.
    PUSH    r19     # R19 will contain a copy of r6.
    PUSH    r20     # R20 will contain a copy of r7.
    mov     r16,r4  # Get format string argument
    movi    r17,0   # Clear argument number.
    mov     r18,r5  # Copy r5 to safe place.
    mov     r19,r6  # Copy r6 to safe place.
    mov     r20,r7  # Copy r7 to safe place.
asm_printf_loop:
    ldb     r4,0(r16)   # Get a byte of format string.
    addi    r16,r16,1   # Point to next byte
    # End of format string is marked by a zero-byte.
    beq     r4,r0,asm_printf_end
    cmpeqi  r9,r4,92    # Check for backslash escape.
    bne     r9,r0,asm_printf_backslash
    cmpeqi  r9,r4,'%'   # Check for percent-sign escape.
    bne     r9,r0,asm_printf_percentsign
asm_printf_doprint:
    # No escapes present, just print the character.
    movia   r8,out_char_uart_0
    callr   r8
    br      asm_printf_loop
asm_printf_backslash:
    # Preload address to out_char_uart_0 into r8.
    movia   r8,out_char_uart_0
    ldb     r4,0(r16)   # Get byte after backslash
    addi    r16,r16,1   # Increase byte count.
    # Having a backslash at the end of the format string
    # is illegal, but must not crash our printf code.
    beq     r4,r0,asm_printf_end
    cmpeqi  r9,r4,'n'   # Newline
    beq     r9,r0,asm_printf_backslash_not_newline
    movi    r4,10       # Newline
    callr   r8
    br      asm_printf_loop
asm_printf_backslash_not_newline:
    cmpeqi  r9,r4,'r'   # Return
    beq     r9,r0,asm_printf_backslash_not_return
    movi    r4,13       # Return
    callr   r8
    br      asm_printf_loop
asm_printf_backslash_not_return:
    # Unknown character after backslash - ignore.
    br      asm_printf_loop
asm_printf_percentsign:
    addi    r17,r17,1   # Increase argument count.
    cmpgei  r8,r17,4    # Check against maximum argument count.
    # If maximum argument count exceeded, print format string.
    bne     r8,r0,asm_printf_doprint
    cmpeqi  r9,r17,1    # Is argument number equal to 1?
    beq     r9,r0,asm_printf_not_r5 # beq jumps if cmpeqi false
    mov     r4,r18      # If yes, get argument from saved copy of r5.
    br      asm_printf_do_conversion
asm_printf_not_r5:
    cmpeqi  r9,r17,2    # Is argument number equal to 2?
    beq     r9,r0,asm_printf_not_r6 # beq jumps if cmpeqi false
    mov     r4,r19      # If yes, get argument from saved copy of r6.
    br      asm_printf_do_conversion
asm_printf_not_r6:
    cmpeqi  r9,r17,3    # Is argument number equal to 3?
    beq     r9,r0,asm_printf_not_r7 # beq jumps if cmpeqi false
    mov     r4,r20       # If yes, get argument from saved copy of r7.
    br      asm_printf_do_conversion
asm_printf_not_r7:
    # This should not be possible.
    # If this strange error happens, print format string.
    br      asm_printf_doprint
asm_printf_do_conversion:
    ldb     r8,0(r16)   # Get byte after percent-sign.
    addi    r16,r16,1   # Increase byte count.
    cmpeqi  r9,r8,'x'   # Check for %x (hexadecimal).
    beq     r9,r0,asm_printf_not_x
    movia   r8,out_hex_uart_0
    callr   r8
    br      asm_printf_loop
asm_printf_not_x:
    cmpeqi  r9,r8,'d'   # Check for %d (decimal).
    beq     r9,r0,asm_printf_not_d
    movia   r8,out_number_uart_0
    callr   r8
    br      asm_printf_loop
asm_printf_not_d:
    cmpeqi  r9,r8,'c'   # Check for %c (character).
    beq     r9,r0,asm_printf_not_c
    # Print character argument.
    br      asm_printf_doprint
asm_printf_not_c:
    cmpeqi  r9,r8,'s'   # Check for %s (string).
    beq     r9,r0,asm_printf_not_s
    movia   r8,out_string_uart_0
    callr   r8
    br      asm_printf_loop
asm_printf_not_s:
asm_printf_unknown:
    # We do not know what to do with other formats.
    # Print the format string text.
    movi    r4,'%'
    movia   r8,out_char_uart_0
    callr   r8
    ldb     r4,-1(r16)
    br      asm_printf_doprint
asm_printf_end:
    POP     r20
    POP     r19
    POP     r18
    POP     r17
    POP     r16
    POP     ra
    ret

#
# End of simplified printf() replacement code.
#
################################################################
.end

निम्न-स्तरीय सी

शीर्ष लेख फ़ाइल


4
यकीन नहीं होता कि यह इलेक्ट्रिकल इंजीनियरिंग का सवाल है। माइक्रोकंट्रोलर प्रोग्रामिंग सवालों का आमतौर पर यहां मनोरंजन किया जाता है, लेकिन ओएस डिजाइन "ऑन-टॉपिक" के किनारे पर जोर दे रहा है।
फिल फ्रॉस्ट

2
एक वास्तविक समय की घड़ी का वास्तविक समय के ओएस के साथ बहुत कम संबंध होता है। शायद आप अपने प्रश्न को अधिक सीधे अपनी वास्तविक समस्या से जोड़ सकते हैं।
फिल फ्रॉस्ट

3
आप कर्नेल के स्थान पर कोर शब्द का उपयोग करने लगते हैं ।
काज

2
वह सही है। "कोर" (या "कोर मेमोरी") का उपयोग चुंबकीय कोर से निर्मित रैम को संदर्भित करने के लिए किया जाता है। फिर यह किसी भी प्रकार की रैम (उदाहरण के लिए यूनिक्स जैसी प्रणालियों पर "कोर डंप") को संदर्भित करने के लिए आया था। आजकल "कोर" शब्द का उपयोग एक चिप पर माइक्रोप्रोसेसर ब्लॉक को संदर्भित करने के लिए किया जाता है जिसमें अन्य ब्लॉक (अन्य कोर सहित) हैं। "एक चिप पर इस प्रणाली में चार कोर, क्रिप्टो करने के लिए एक ब्लॉक, दो UARTS और एक ईथरनेट नियंत्रक है।"
काज

जवाबों:


19

एक (कठिन) वास्तविक समय प्रणाली का मुद्दा यह है कि उसे निश्चित समय के भीतर कुछ चीजें करनी चाहिए। यदि बाद में किया जाता है, तो भी थोड़ा सा, सिस्टम बेकार है। एक कार एयरबैग के बारे में सोचें जो आपके सिर के स्टीयरिंग व्हील से टकरा जाने के बाद उड़ती है ।

एक वास्तविक समय ओएस को अधिकतम विलंब के लिए निश्चित गारंटी देनी चाहिए, जिसमें ओएस लेट जैसे कि इंटरप्ट लेटेंसी, टास्क स्विचिंग इत्यादि करना है, इसी तरह से आने वाली लाइब्रेरियों को इस तरह की गारंटी प्रदान करनी चाहिए।

गैर-वास्तविक समय के ओएसएएस आमतौर पर औसत थ्रूपुट को अधिकतम करने की कोशिश करते हैं । तीन डिस्क रीड पर विचार करें, जो या तो 1 एमएस, 1 एमएस, और 5 एमएस में किया जा सकता है या वैकल्पिक रूप से 3 एमएस, 3 एमएस और 3 एमएस में किया जा सकता है। एक गैर-वास्तविक समय वाला ओएस पहले विकल्प को पसंद करेगा, क्योंकि कुल काम 7 एमएस में किया जाता है। एक वास्तविक समय ओएस शायद दूसरा विकल्प पसंद करेगा, क्योंकि अधिकतम डिस्क रीड विलंब में 3 एमएस है।

जहां तक ​​मुझे पता है कि लिनक्स एक वास्तविक समय ऑपरेटिंग सिस्टम नहीं है। यह संभावना नहीं है कि यह कभी भी होगा, क्योंकि इसका सामान्य उपयोग डेस्कटॉप या सर्वर के रूप में है। प्रतिक्रिया समय पर ऊपरी सीमा से उच्च थ्रूपुट से अधिक लाभ दोनों का उपयोग करता है।


6
Linux ने कुछ महत्वपूर्ण बदलाव किए (2002 के आसपास सही लगता है) इसे और अधिक (नरम) वास्तविक समय बनाने के लिए। कई आम इंटरप्ट हैंडलर को प्रीपेप्टेबल (डिस्क आईओ, आदि) बनाने के लिए बहुत सारे काम किए गए और अतिरिक्त शेड्यूलर प्राथमिकताओं को जोड़ा गया, ताकि रियलटाइम प्रदर्शन की आवश्यकता वाले कार्यों को कम-प्राथमिकता वाले कार्यों से पहले किया जा सके। यह एक सॉफ्ट रियलटाइम सिस्टम है, हार्ड रियलटाइम सिस्टम नहीं है, और ड्राइविंग उपयोग का मामला डीएडब्ल्यू और सिंथेसाइज़र के लिए रियल टाइम ऑडियो प्रोसेसिंग था।
फिल फ्रॉस्ट

2
इसके अलावा, RTLinux RTLinux is a hard realtime RTOS microkernel that runs the entire Linux operating system as a fully preemptive process. It is one hard realtime variant of Linux, among several, that makes it possible to control robots, data acquisition systems, manufacturing plants, and other time-sensitive instruments and machines.
कॉनर वुल्फ

1
उस मामले में हालांकि, यह अनुसूचक लगता है पूरे लिनक्स कर्नेल प्रति-empts, तो बुला linux पहलू वास्तविक समय एक सा गलत लगता है।
कॉनर वुल्फ

2
वास्तविक समय के ओएस का उपयोग करने के क्या फायदे हैं, जो वास्तविक समय में होने वाली चीजों के विपरीत होने के कारण बाधित हैंडलर द्वारा कार्यान्वित किया जाता है ओएस के बारे में बहुत कम या कुछ भी नहीं पता है [संभवत: एक क्षमता से परे है कि क्या ओएस को बंद करने से बचना चाहिए। नीचे या थ्रॉटलिंग बैक सिस्टम घड़ियों की उन्हें आवश्यकता हो सकती है]? क्या ओएस मुख्य रूप से उपयोगी हो जाता है जब हार्डवेयर टाइमर, या कार्यों के बदलते सेट, या क्या से अधिक वास्तविक समय के कार्य होते हैं?
सुपरकाट

5
@ सुपरकैट: जब आपके आवेदन के भीतर सभी कार्य स्वतंत्र हों (व्यवधान दिनचर्या जो बिना किसी बातचीत के पूरा हो सके) कोई फायदा नहीं है। एक आरटीओएस का बिंदु संचार और सिंक्रनाइज़ेशन तंत्र है जिसका उपयोग कार्यों के बीच बातचीत को लागू करने के लिए किया जा सकता है।
राउटर वैन ओइजेन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.