lkml.org 
[lkml]   [2007]   [Feb]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch 07/12] syslets: x86, add create_async_thread() method
    From: Ingo Molnar <mingo@elte.hu>

    add the create_async_thread() way of creating kernel threads:
    these threads first execute a kernel function and when they
    return from it they execute user-space.

    An architecture must implement this interface before it can turn
    CONFIG_ASYNC_SUPPORT on.

    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
    ---
    arch/i386/kernel/entry.S | 25 +++++++++++++++++++++++++
    arch/i386/kernel/process.c | 31 +++++++++++++++++++++++++++++++
    include/asm-i386/processor.h | 17 +++++++++++++++++
    include/asm-i386/unistd.h | 10 ++++++++++
    4 files changed, 83 insertions(+)

    Index: linux/arch/i386/kernel/entry.S
    ===================================================================
    --- linux.orig/arch/i386/kernel/entry.S
    +++ linux/arch/i386/kernel/entry.S
    @@ -1034,6 +1034,31 @@ ENTRY(kernel_thread_helper)
    CFI_ENDPROC
    ENDPROC(kernel_thread_helper)

    +ENTRY(async_thread_helper)
    + CFI_STARTPROC
    + /*
    + * Allocate space on the stack for pt-regs.
    + * sizeof(struct pt_regs) == 64, and we've got 8 bytes on the
    + * kernel stack already:
    + */
    + subl $64-8, %esp
    + CFI_ADJUST_CFA_OFFSET 64-8
    + movl %edx,%eax
    + push %edx
    + CFI_ADJUST_CFA_OFFSET 4
    + call *%ebx
    + addl $4, %esp
    + CFI_ADJUST_CFA_OFFSET -4
    +
    + movl %eax, PT_EAX(%esp)
    +
    + GET_THREAD_INFO(%ebp)
    +
    + jmp syscall_exit
    + CFI_ENDPROC
    +ENDPROC(async_thread_helper)
    +
    +
    .section .rodata,"a"
    #include "syscall_table.S"

    Index: linux/arch/i386/kernel/process.c
    ===================================================================
    --- linux.orig/arch/i386/kernel/process.c
    +++ linux/arch/i386/kernel/process.c
    @@ -355,6 +355,37 @@ int kernel_thread(int (*fn)(void *), voi
    EXPORT_SYMBOL(kernel_thread);

    /*
    + * This gets run with %ebx containing the
    + * function to call, and %edx containing
    + * the "args".
    + */
    +extern void async_thread_helper(void);
    +
    +/*
    + * Create an async thread
    + */
    +int create_async_thread(long (*fn)(void *), void * arg, unsigned long flags)
    +{
    + struct pt_regs regs;
    +
    + memset(&regs, 0, sizeof(regs));
    +
    + regs.ebx = (unsigned long) fn;
    + regs.edx = (unsigned long) arg;
    +
    + regs.xds = __USER_DS;
    + regs.xes = __USER_DS;
    + regs.xfs = __KERNEL_PDA;
    + regs.orig_eax = -1;
    + regs.eip = (unsigned long) async_thread_helper;
    + regs.xcs = __KERNEL_CS | get_kernel_rpl();
    + regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2;
    +
    + /* Ok, create the new task.. */
    + return do_fork(flags, 0, &regs, 0, NULL, NULL);
    +}
    +
    +/*
    * Free current thread data structures etc..
    */
    void exit_thread(void)
    Index: linux/include/asm-i386/processor.h
    ===================================================================
    --- linux.orig/include/asm-i386/processor.h
    +++ linux/include/asm-i386/processor.h
    @@ -472,6 +472,11 @@ extern void prepare_to_copy(struct task_
    */
    extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);

    +/*
    + * create an async thread:
    + */
    +extern int create_async_thread(long (*fn)(void *), void * arg, unsigned long flags);
    +
    extern unsigned long thread_saved_pc(struct task_struct *tsk);
    void show_trace(struct task_struct *task, struct pt_regs *regs, unsigned long *stack);

    @@ -504,6 +509,18 @@ unsigned long get_wchan(struct task_stru
    #define KSTK_EIP(task) (task_pt_regs(task)->eip)
    #define KSTK_ESP(task) (task_pt_regs(task)->esp)

    +/*
    + * Register access methods for async syscall support.
    + *
    + * Note, task_stack_reg() must not be an lvalue, hence this macro:
    + */
    +#define task_stack_reg(t) \
    + ({ unsigned long __esp = task_pt_regs(t)->esp; __esp; })
    +#define set_task_stack_reg(t, new_stack) \
    + do { task_pt_regs(t)->esp = (new_stack); } while (0)
    +#define task_ip_reg(t) task_pt_regs(t)->eip
    +#define task_ret_reg(t) task_pt_regs(t)->eax
    +

    struct microcode_header {
    unsigned int hdrver;
    Index: linux/include/asm-i386/unistd.h
    ===================================================================
    --- linux.orig/include/asm-i386/unistd.h
    +++ linux/include/asm-i386/unistd.h
    @@ -1,6 +1,8 @@
    #ifndef _ASM_I386_UNISTD_H_
    #define _ASM_I386_UNISTD_H_

    +#include <linux/linkage.h>
    +
    /*
    * This file contains the system call numbers.
    */
    @@ -330,6 +332,14 @@

    #define NR_syscalls 320

    +#ifndef __ASSEMBLY__
    +
    +typedef asmlinkage long (*syscall_fn_t)(long, long, long, long, long, long);
    +
    +extern syscall_fn_t sys_call_table[NR_syscalls];
    +
    +#endif
    +
    #define __ARCH_WANT_IPC_PARSE_VERSION
    #define __ARCH_WANT_OLD_READDIR
    #define __ARCH_WANT_OLD_STAT
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2007-02-28 22:55    [W:0.045 / U:0.012 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site