Changeset 25451

Show
Ignore:
Timestamp:
05/11/08 11:25:35 (5 days ago)
Author:
bonefish
Message:
* For each userland team the kernel creates an area in the userland
  address space that is fully locked and marked B_KERNEL_AREA. It can
  thus be accessed by the kernel without additional checks.
* For each userland thread we do create a user_thread structure in that
  area. The structure is accessible from userland via TLS, using the
  private get_user_thread() function.
* Introduced private userland functions [un]defer_signals(). They can be
  used to cheaply disable/re-enable signal delivery. They use the
  user_thread::defer_signals/pending_signals fields which are
  checked/updated by the kernel.
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • haiku/trunk/headers/private/kernel/arch/x86/arch_kernel.h

    r25358 r25451  
    3333#define USER_TOP      (USER_BASE + USER_SIZE) 
    3434 
    35 #define USER_STACK_REGION 0x70000000 
    36 #define USER_STACK_REGION_SIZE (USER_TOP - USER_STACK_REGION) 
     35#define KERNEL_USER_DATA_BASE   0x6fff0000 
     36#define USER_STACK_REGION               0x70000000 
     37#define USER_STACK_REGION_SIZE  (USER_TOP - USER_STACK_REGION) 
    3738 
    3839#endif  /* _KERNEL_ARCH_x86_KERNEL_H */ 
  • haiku/trunk/headers/private/kernel/team.h

    r24335 r25451  
    4848                        void *data); 
    4949 
     50struct user_thread* team_allocate_user_thread(struct team* team); 
     51void team_free_user_thread(struct thread* thread); 
     52 
    5053// used in syscalls.c 
    5154thread_id _user_load_image(int32 argCount, const char **args, int32 envCount, 
  • haiku/trunk/headers/private/kernel/thread_types.h

    r25326 r25451  
    7272struct realtime_sem_context;    // defined in realtime_sem.cpp 
    7373struct select_info; 
     74struct user_thread;                             // defined in libroot/user_thread.h 
    7475 
    7576struct death_entry { 
     
    165166#endif  // __cplusplus 
    166167 
     168 
     169struct free_user_thread { 
     170        struct free_user_thread*        next; 
     171        struct user_thread*                     thread; 
     172}; 
    167173 
    168174struct team { 
     
    200206        struct arch_team arch_info; 
    201207 
     208        addr_t                  user_data; 
     209        area_id                 user_data_area; 
     210        size_t                  user_data_size; 
     211        size_t                  used_user_data; 
     212        struct free_user_thread* free_user_threads; 
     213 
    202214        struct team_debug_info debug_info; 
    203215 
     
    240252        bool                    signal_stack_enabled; 
    241253 
     254        bool                    in_kernel; 
     255        bool                    was_yielded; 
     256 
     257        struct user_thread*     user_thread; 
     258 
    242259        struct { 
    243260                uint8           parameters[32]; 
    244261        } syscall_restart; 
    245  
    246         bool                    in_kernel; 
    247         bool                    was_yielded; 
    248262 
    249263        struct { 
  • haiku/trunk/headers/private/kernel/tls.h

    r3073 r25451  
    1818        TLS_ERRNO_SLOT, 
    1919        TLS_ON_EXIT_THREAD_SLOT, 
     20        TLS_USER_THREAD_SLOT, 
    2021 
    2122        // Note: these entries can safely be changed between 
  • haiku/trunk/src/system/kernel/arch/x86/arch_thread.cpp

    r24487 r25451  
    310310arch_thread_init_tls(struct thread *thread) 
    311311{ 
    312         uint32 tls[TLS_THREAD_ID_SLOT + 1]; 
     312        uint32 tls[TLS_USER_THREAD_SLOT + 1]; 
    313313        int32 i; 
    314314 
     
    317317 
    318318        // initialize default TLS fields 
     319        memset(tls, 0, sizeof(tls)); 
    319320        tls[TLS_BASE_ADDRESS_SLOT] = thread->user_local_storage; 
    320321        tls[TLS_THREAD_ID_SLOT] = thread->id; 
     322        tls[TLS_USER_THREAD_SLOT] = (addr_t)thread->user_thread; 
    321323 
    322324        return user_memcpy((void *)thread->user_local_storage, tls, sizeof(tls)); 
  • haiku/trunk/src/system/kernel/Jamfile

    r25375 r25451  
    1111} 
    1212 
     13UsePrivateHeaders libroot ; 
    1314UsePrivateHeaders shared ; 
    1415UsePrivateHeaders runtime_loader ; 
  • haiku/trunk/src/system/kernel/signal.cpp

    r25228 r25451  
    2525#include <tracing.h> 
    2626#include <user_debugger.h> 
     27#include <user_thread.h> 
    2728#include <util/AutoLock.h> 
    2829 
     
    4344        (SIGNAL_TO_MASK(SIGCHLD) | SIGNAL_TO_MASK(SIGWINCH) \ 
    4445        | SIGNAL_TO_MASK(SIGCONT)) 
     46#define NON_DEFERRABLE_SIGNALS  \ 
     47        (KILL_SIGNALS                           \ 
     48        | SIGNAL_TO_MASK(SIGILL)        \ 
     49        | SIGNAL_TO_MASK(SIGFPE)        \ 
     50        | SIGNAL_TO_MASK(SIGSEGV)) 
    4551 
    4652 
     
    270276        if (signalMask == 0) 
    271277                return 0; 
     278 
     279        if (thread->user_thread->defer_signals > 0 
     280                && (signalMask & NON_DEFERRABLE_SIGNALS) == 0) { 
     281                thread->user_thread->pending_signals = signalMask; 
     282                return 0; 
     283        } 
     284 
     285        thread->user_thread->pending_signals = 0; 
    272286 
    273287        bool restart = (atomic_and(&thread->flags, 
  • haiku/trunk/src/system/kernel/team.cpp

    r25336 r25451  
    11/* 
     2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. 
    23 * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. 
    34 * Distributed under the terms of the MIT License. 
     
    3637#include <tracing.h> 
    3738#include <user_runtime.h> 
     39#include <user_thread.h> 
    3840#include <usergroup.h> 
    3941#include <vfs.h> 
     
    7072        addr_t          user_local_storage; 
    7173        sigset_t        sig_block_mask; 
     74        struct user_thread* user_thread; 
    7275 
    7376        struct arch_fork_arg arch_info; 
     
    831834        team->flags = 0; 
    832835        team->death_sem = -1; 
     836        team->user_data_area = -1; 
     837        team->user_data = 0; 
     838        team->used_user_data = 0; 
     839        team->user_data_size = 0; 
     840        team->free_user_threads = NULL; 
    833841 
    834842        team->supplementary_groups = NULL; 
     
    912920                delete entry; 
    913921 
     922        while (free_user_thread* entry = team->free_user_threads) { 
     923                team->free_user_threads = entry->next; 
     924                free(entry); 
     925        } 
     926 
    914927        malloc_referenced_release(team->supplementary_groups); 
    915928 
     
    933946 
    934947        return size + (argc + 1) * sizeof(char *) + sizeof(struct user_space_program_args); 
     948} 
     949 
     950 
     951static status_t 
     952create_team_user_data(struct team* team) 
     953{ 
     954        void* address = (void*)KERNEL_USER_DATA_BASE; 
     955        size_t size = 4 * B_PAGE_SIZE; 
     956        team->user_data_area = create_area_etc(team, "user area", &address, 
     957                B_BASE_ADDRESS, size, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA); 
     958        if (team->user_data_area < 0) 
     959                return team->user_data_area; 
     960 
     961        team->user_data = (addr_t)address; 
     962        team->used_user_data = 0; 
     963        team->user_data_size = size; 
     964        team->free_user_threads = NULL; 
     965 
     966        return B_OK; 
     967} 
     968 
     969 
     970static void 
     971delete_team_user_data(struct team* team) 
     972{ 
     973        if (team->user_data_area >= 0) { 
     974                delete_area_etc(team, team->user_data_area); 
     975                team->user_data = 0; 
     976                team->used_user_data = 0; 
     977                team->user_data_size = 0; 
     978                team->user_data_area = -1; 
     979                while (free_user_thread* entry = team->free_user_threads) { 
     980                        team->free_user_threads = entry->next; 
     981                        free(entry); 
     982                } 
     983        } 
    935984} 
    936985 
     
    10051054        TRACE(("team_create_thread_start: entry thread %ld\n", t->id)); 
    10061055 
     1056        // get a user thread for the main thread 
     1057        t->user_thread = team_allocate_user_thread(team); 
     1058 
    10071059        // create an initial primary stack area 
    10081060 
     
    12171269                threadName = args[0]; 
    12181270 
     1271        // create the user data area 
     1272        status = create_team_user_data(team); 
     1273        if (status != B_OK) 
     1274                goto err4; 
     1275 
    12191276        // Create a kernel thread, but under the context of the new team 
    12201277        // The new thread will take over ownership of teamArgs 
     
    12231280        if (thread < 0) { 
    12241281                status = thread; 
    1225                 goto err4
     1282                goto err5
    12261283        } 
    12271284 
     
    12651322        return thread; 
    12661323 
     1324err5: 
     1325        delete_team_user_data(team); 
    12671326err4: 
    12681327        vm_put_address_space(team->address_space); 
     
    13631422        user_debug_prepare_for_exec(); 
    13641423 
     1424        delete_team_user_data(team); 
    13651425        vm_delete_areas(team->address_space); 
    13661426        delete_owned_ports(team->id); 
     
    13711431        team->realtime_sem_context = NULL; 
    13721432 
     1433        status = create_team_user_data(team); 
     1434        if (status != B_OK) { 
     1435                // creating the user data failed -- we're toast 
     1436                // TODO: We should better keep the old user area in the first place. 
     1437                exit_thread(status); 
     1438                return status; 
     1439        } 
     1440 
    13731441        user_debug_finish_after_exec(); 
    13741442 
     
    14231491        thread->user_local_storage = forkArgs->user_local_storage; 
    14241492        thread->sig_block_mask = forkArgs->sig_block_mask; 
     1493        thread->user_thread = forkArgs->user_thread; 
    14251494 
    14261495        arch_thread_init_tls(thread); 
     
    15101579        // ToDo: all stacks of other threads than the current one could be left out 
    15111580 
     1581        forkArgs->user_thread = NULL; 
     1582 
    15121583        cookie = 0; 
    15131584        while (get_next_area_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { 
     
    15201591                } 
    15211592 
    1522                 if (info.area == parentThread->user_stack_area) 
     1593                if (info.area == parentThread->user_stack_area) { 
    15231594                        forkArgs->user_stack_area = area; 
     1595                } else if (info.area == parentTeam->user_data_area) { 
     1596                        team->user_data = (addr_t)address; 
     1597                        team->used_user_data = 0; 
     1598                        team->user_data_size = info.size; 
     1599                        team->user_data_area = area; 
     1600                        team->free_user_threads = NULL; 
     1601                        forkArgs->user_thread = team_allocate_user_thread(team); 
     1602                } 
    15241603        } 
    15251604 
    15261605        if (status < B_OK) 
    15271606                goto err4; 
     1607 
     1608        if (forkArgs->user_thread == NULL) { 
     1609#if KDEBUG 
     1610                panic("user data area not found, parent area is %ld", 
     1611                        parentTeam->user_data_area); 
     1612#endif 
     1613                status = B_ERROR; 
     1614                goto err4; 
     1615        } 
    15281616 
    15291617        forkArgs->user_stack_base = parentThread->user_stack_base; 
     
    25562644        free(watcher); 
    25572645        return B_OK; 
     2646} 
     2647 
     2648 
     2649/*!     The team lock must be held or the team must still be single threaded. 
     2650*/ 
     2651struct user_thread* 
     2652team_allocate_user_thread(struct team* team) 
     2653{ 
     2654        if (team->user_data == 0) 
     2655                return NULL; 
     2656 
     2657        user_thread* thread = NULL; 
     2658 
     2659        // take an entry from the free list, if any 
     2660        if (struct free_user_thread* entry = team->free_user_threads) { 
     2661                thread = entry->thread; 
     2662                team->free_user_threads = entry->next; 
     2663                deferred_free(entry); 
     2664                return thread; 
     2665        } else { 
     2666                // enough space left? 
     2667                size_t needed = _ALIGN(sizeof(user_thread)); 
     2668                if (team->user_data_size - team->used_user_data < needed) 
     2669                        return NULL; 
     2670                // TODO: This imposes a per team thread limit! We should resize the 
     2671                // area, if necessary. That's problematic at this point, though, since 
     2672                // we've got the team lock. 
     2673 
     2674                thread = (user_thread*)(team->user_data + team->used_user_data); 
     2675                team->used_user_data += needed; 
     2676        } 
     2677 
     2678        thread->defer_signals = 0; 
     2679        thread->pending_signals = 0; 
     2680        thread->wait_status = B_OK; 
     2681 
     2682        return thread; 
     2683} 
     2684 
     2685 
     2686/*!     The team lock must not be held. \a thread must be the current thread. 
     2687*/ 
     2688void 
     2689team_free_user_thread(struct thread* thread) 
     2690{ 
     2691        user_thread* userThread = thread->user_thread; 
     2692        if (userThread == NULL) 
     2693                return; 
     2694 
     2695        // create a free list entry 
     2696        free_user_thread* entry 
     2697                = (free_user_thread*)malloc(sizeof(free_user_thread)); 
     2698        if (entry == NULL) { 
     2699                // we have to leak the user thread :-/ 
     2700                return; 
     2701        } 
     2702 
     2703        InterruptsSpinLocker _(team_spinlock); 
     2704 
     2705        entry->thread = userThread; 
     2706        entry->next = thread->team->free_user_threads; 
     2707        thread->team->free_user_threads = entry; 
    25582708} 
    25592709 
  • haiku/trunk/src/system/kernel/thread.cpp

    r25434 r25451  
    445445        // look at the team, make sure it's not being deleted 
    446446        team = team_get_team_struct_locked(attributes.team); 
    447         if (team != NULL && team->state != TEAM_STATE_DEATH) { 
     447 
     448        if (team == NULL || team->state == TEAM_STATE_DEATH) 
     449                abort = true; 
     450 
     451        if (!abort && !kernel) { 
     452                thread->user_thread = team_allocate_user_thread(team); 
     453                abort = thread->user_thread == NULL; 
     454        } 
     455 
     456        if (!abort) { 
    448457                // Debug the new thread, if the parent thread required that (see above), 
    449458                // or the respective global team debug flag is set. But only, if a 
     
    458467 
    459468                insert_thread_into_team(team, thread); 
    460         } else 
    461                 abort = true; 
     469        } 
    462470 
    463471        RELEASE_TEAM_LOCK(); 
     
    14081416                        // this was the main thread in this team, so we will delete that as well 
    14091417                        deleteTeam = true; 
    1410                 } else 
     1418                } else { 
    14111419                        threadDeathEntry = (death_entry*)malloc(sizeof(death_entry)); 
     1420                        team_free_user_thread(thread); 
     1421                } 
    14121422 
    14131423                // remove this thread from the current team and add it to the kernel 
     
    29382948        return common_setrlimit(resource, &resourceLimit); 
    29392949} 
    2940