Wednesday, April 27, 2016

C++

Monday, April 25, 2016

program, assembly, simple1.c

simple1.c

int add(int i, int j);

int main()
{
    int i, j;
    i++;
    j = 10;
    j = i;
    j = add(i,j);
    return 0;
}

int add(int i, int j)
{
    int result;
    result = i+j;
    return result;
}

simple1.s

    .file    "simple1.c"
    .text
    .globl    main
    .type    main, @function
main:
.LFB0:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    addl    $1, -8(%rbp)
    movl    $10, -4(%rbp)
    movl    -8(%rbp), %eax
    movl    %eax, -4(%rbp)
    movl    -4(%rbp), %edx
    movl    -8(%rbp), %eax
    movl    %edx, %esi
    movl    %eax, %edi
    call    add
    movl    %eax, -4(%rbp)
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size    main, .-main
    .globl    add
    .type    add, @function
add:
.LFB1:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    %edi, -20(%rbp)
    movl    %esi, -24(%rbp)
    movl    -24(%rbp), %eax
    movl    -20(%rbp), %edx
    addl    %edx, %eax
    movl    %eax, -4(%rbp)
    movl    -4(%rbp), %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size    add, .-add
    .ident    "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4"
    .section    .note.GNU-stack,"",@progbits

nm simple1.o

0000000000000032 T add
0000000000000000 T main

proram, assembly, simple.c

Simple.c

int main()
{
    int i, j;
    i++;
    j = 10;
    j = i;

    return 0;
}

Simple.s

   .file   "simple.c"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    addl    $1, -8(%rbp)
    movl    $10, -4(%rbp)
    movl    -8(%rbp), %eax
    movl    %eax, -4(%rbp)
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4"
    .section    .note.GNU-stack,"",@progbits

nm simple.o

0000000000000000 T main


Friday, April 22, 2016

Kernel Synchronization


  • critical regions: Code paths that access and manipulate shared data are called critical regions
  • atomic operation: operations complete without interruption as if the entire critical region were one indivisible instruction
  • Race condition: it is the condition when two threads of execution to be simultaneously executing within the same critical region.
  • If the critical region is a very minimal instruction, making the execution as atomic operation will avoid the race condition. For eg, i++ will be performed by 3 or 4 instructions in assembly language. This can be made as an atomic operation for synchronization.
  • The kernel provides two sets of interfaces for atomic operations—one that operates on integers and another that operates on individual bits.These interfaces are implemented on every architecture that Linux supports. Most architectures contain instructions that provide atomic versions of simple arithmetic operations. Other architectures, lacking direct atomic operations, provide an operation to lock the memory bus for a single operation, thus guaranteeing that another memory-affecting operation cannot occur simultaneously.
  • Generally, a few instructions can be made atomic by the processor. When a huge instructions are to be synchronized, a locking mechanism is required. In this case only the locking operation will be atomic.
  • Locking mechanisms can be different that when a thread finds that a critical region is locked, it can busy wait(eg, spin lock) or sleep.
  • On the popular x86 architecture, locks are implemented using such an instruction called compare and exchange.
  • Causes of concurrency in user space programs.
    • true concurrency occurs because of multi processors.
    • pseudo-concurrency occurs because of preemption(or yielding) or receiving of signals in a user space program.
  • Causes of concurrency in kernel space programs.
    • Interrupts— An interrupt can occur asynchronously at almost any time, interrupting the currently executing code.
    • Softirqs and tasklets— The kernel can raise or schedule a softirq or tasklet at almost any time, interrupting the currently executing code.
    • Kernel preemption— Because the kernel is preemptive, one task in the kernel can preempt another.
    • Sleeping and synchronization with user-space— A task in the kernel can sleep and thus invoke the scheduler, resulting in the running of a new process.
    • Symmetrical multiprocessing— Two or more processors can execute kernel code at exactly the same time.
  • The term lock contention, or simply contention, describes a lock currently in use but that another thread is trying to acquire.
  • spin lock:
    • A spin lock is a lock that can be held by at most one thread of execution.
    • If a thread of execution attempts to acquire a spin lock while it is already held, which is called contended, the thread busy loops—spins—waiting for the lock to become available.
    • It is not wise to hold a spin lock for a long time.This is the nature of the spin lock: a lightweight single-holder lock that should be held for short durations.
    • Making the process to sleep if the lock is already contended incurs a bit of overhead—most notably the two context switches required to switch out of and back into the blocking thread, which is certainly a lot more code than the handful of lines used to implement a spin lock.Therefore, it is wise to hold spin locks for less than the duration of two context switches.
    • On uniprocessor machines, the locks compile away and do not exist; they simply act as markers to disable and enable kernel preemption. If kernel preempt is turned off, the locks compile away entirely.
    • Spin locks can be used in interrupt handlers, whereas semaphores cannot be used because they sleep.
    • If a lock is used in an interrupt handler, you must also disable local interrupts (interrupt requests on the current processor) before obtaining the lock. Otherwise, it is possible for an interrupt handler to interrupt kernel code while the lock is held and attempt to reacquire the lock.The interrupt handler spins, waiting for the lock to become
      available.The lock holder, however, does not run until the interrupt handler completes. This is an example of the double-acquire deadlock. Note that you need to disable interrupts only on the current processor. If an interrupt occurs on a different processor, and it spins on the same lock, it does not prevent the lock holder (which is on a different processor) from eventually releasing the lock.
    • Because a bottom half might preempt process context code, if data is shared between a bottom-half process context, you must protect the data in process context with both a lock and the disabling of bottom halves. Likewise, because an interrupt handler might preempt a bottom half, if data is shared between an interrupt handler and a bottom half, you must both obtain the appropriate lock and disable interrupts
    • reader-writer spin lock
  •  

Sunday, April 10, 2016

Kernel Stack


  • https://www.kernel.org/doc/Documentation/x86/kernel-stacks
  • Like all other architectures, x86_64 has a kernel stack for every
    active thread.  These thread stacks are THREAD_SIZE (2*PAGE_SIZE) big.
    These stacks contain useful data as long as a thread is alive or a
    zombie.
  • While the thread is in user space the kernel stack is empty
    except for the thread_info structure at the bottom.
    

Sunday, April 03, 2016

General Scraps


  • Processor priority in Linux
    • The first is the nice value, a number from -20 to +19 with a default of 0. Larger nice values correspond to a lower priorityyou are being nice to the other processes on the system. Processes with a lower nice value (higher priority) run before processes with a higher nice value (lower priority). The nice value also helps determine how long a timeslice the process receives. A process with a nice value of -20 receives the maximum possible timeslice, whereas a process with a nice value of 19 receives the minimum possible timeslice. Nice values are the standard priority range used in all Unix systems.
    • The second range is the real-time priority. The values are configurable, but by default range from 0 to 99. All real-time processes are at a higher priority than normal processes.
    • Real Time values + nice value together.
    • Real Time process command
    • The chrt command
      • To set scheduling policy to SCHED_FIFO, enter:
        chrt -f -p [1..99] {pid}
        
        To set scheduling policy to SCHED_RR, enter:
        chrt -r -p [1..99] {pid}
  • asmlinkage keyworkd in system call
  • system call is reentrant
  • Seeing assembly and register values in GDB and description about assembly code
                  https://www.recurse.com/blog/7-understanding-c-by-learning-assembly