/* Ten plik zawiera większość podstawowych struktur danych wykorzystywanych przez wątki */ /* Linuxthreads - a simple clone()-based implementation of Posix */ /* threads for Linux. */ /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ /* */ /* This program is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU Library General Public License */ /* as published by the Free Software Foundation; either version 2 */ /* of the License, or (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU Library General Public License for more details. */ /* Internal data structures */ /* Includes */ #include <sys/types.h> #include <setjmp.h> #include <signal.h> #include <gnu-stabs.h> /* for weak_alias */ #include <linux/mm.h> #include "pt-machine.h" /* Struktura argumentów przekazywana do funkcji woływanej przez wątek */ /* Arguments passed to thread creation routine */ struct pthread_start_args { void * (*start_routine)(void *); /* function to run */ /* funkcja do uruchomienia */ void * arg; /* its argument */ /* jej argumenty */ sigset_t mask; /* initial signal mask for thread */ /* początkowa maska sygnałów */ int schedpolicy; /* initial scheduling policy (if any) */ /* początkowy system zarządzania wątkiem (o ile jest podany) */ struct sched_param schedparam; /* initial scheduling parameters (if any) */ /* początkowe parametry zarządzania (o ile są podane) */ }; /* Domyślne wartości powyższej struktury */ #define PTHREAD_START_ARGS_INITIALIZER { NULL, NULL, 0, 0, { 0 } } /* Dane wątków trzymane są w tablicy tablic. Tablica pierwszego poziomu zawiera wskaźniki do dynamicznie tworzonych tablic o określonym rozmiarze (tak więc mamy tu zaimplementowaną tablice mieszającą). Każda z tablic drugiego poziomu zawiera PTHREAD_KEY_2NDLEVEL_SIZE - ta wielkość nie powinna być zbyt duża! */ /* We keep thread specific data in a special data structure, a two-level array. The top-level array contains pointers to dynamically allocated arrays of a certain number of data pointers. So we can implement a sparse array. Each dynamic second-level array has PTHREAD_KEY_2NDLEVEL_SIZE entries. This value shouldn't be too large. */ #define PTHREAD_KEY_2NDLEVEL_SIZE 32 /* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE keys in each subarray. */ /* Rozmiar tablicy pierwszego poziomu musi być taki, aby w tablicy tablic można było pomieścić PTHREAD_KEY_MAX elementów */ /* The type of thread descriptors */ typedef struct _pthread_descr_struct * pthread_descr; struct _pthread_descr_struct { pthread_descr p_nextlive, p_prevlive; /* Double chaining of active threads */ /* Lista cykliczna aktywnych wątków */ pthread_descr p_nextwaiting; /* Next element in the queue holding the thr */ /* Następny element w kolejce oczekujących*/ pthread_t p_tid; /* Thread identifier */ /* Identyfikator wątku */ int p_pid; /* PID of Unix process */ /* PID procesu wykonującego wątek */ int p_priority; /* Thread priority (== 0 if not realtime) */ /* Priorytet dostępu do procesora */ int * p_spinlock; /* Spinlock for synchronized accesses */ /* Semafor binarny dla synchronizacji dostępu */ int p_signal; /* last signal received */ /* Ostatni odebrany sygnał */ sigjmp_buf * p_signal_jmp; /* where to siglongjmp on a signal or NULL */ sigjmp_buf * p_cancel_jmp; /* where to siglongjmp on a cancel or NULL */
/* adresy skoków w przypadku przerwania lub odebrania sygnału */ char p_terminated; /* true if terminated e.g. by pthread_exit */ /* 1 jesli wątek zakończony, 0 wpp. */ char p_detached; /* true if detached */ /* 1 jesli wątek odłączony, 0 wpp. */ char p_exited; /* true if the assoc. process terminated */ /* 1 jeśli funkcja wykonywana przez wąup1;tek zakończona, 0 wpp. */ void * p_retval; /* placeholder for return value */ int p_retcode; /* placeholder for return code */ /* Miejsca na zwracaną przez funkcję wątku wartość i kod powrotu */ pthread_descr p_joining; /* thread joining on that thread or NULL */ /* Wątek czekający na nasze zakończenie */ struct _pthread_cleanup_buffer * p_cleanup; /* cleanup functions */ /* Lista funkcji "sprzątających" */ char p_cancelstate; /* cancellation state */ /* 0 jeśli przerwanie niemożliwe, 1 - możliwe */ char p_canceltype; /* cancellation type (deferred/async) */ /* 0 jeśli usunięcie wątku odroczone, 1 jeśli usunięcie wątku natychmiastowe */ char p_canceled; /* cancellation request pending */ /* 1 jeśli wąp1;tek przerwany, 0 wpp. */ int p_errno; /* error returned by last system call */ /* Błąd w ostatnio wywołanej funkcji systemowej */ int p_h_errno; /* error returned by last netdb function */ /* Błąd w ostatnio wywołanej funkcji sieciowej */ struct pthread_start_args p_start_args; /* arguments for thread creation */ /*** parametry utworzenia wątku */ void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */ /* Dane wątku */ }; typedef struct pthread_handle_struct * pthread_handle; struct pthread_handle_struct { int h_spinlock; /* Spinlock for sychronized access */ /* Semafor binarny dla synchronizacji dostępu */ pthread_descr h_descr; /* Thread descriptor or NULL if invalid */ /* Dane opisują;ce wątek */ }; /* The type of messages sent to the thread manager thread */ /* Dane opisujące zlecenie wysyłane do wątku-zarządcy */ struct pthread_request { pthread_descr req_thread; /* Thread doing the request */ enum { /* Request kind */ REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT } req_kind; union { /* Arguments for request */ struct { /* For REQ_CREATE: */ const pthread_attr_t * attr; /* thread attributes */ void * (*fn)(void *); /* start function */ void * arg; /* argument to start function */ sigset_t mask; /* signal mask */ } create; struct { /* For REQ_FREE: */ pthread_descr thread; /* descriptor of thread to free */ } free; struct { /* For REQ_PROCESS_EXIT: */ int code; /* exit status */ } exit; } req_args; }; /* Signals used for suspend/restart and for cancellation notification. FIXME: shoud use new, unallocated signals. */ /* Definicja używanych sygnałów. UWAGA!!! Nie używać tych sygnałów w swoich programach wykorzystujących Linuxthreads!!! */ #define PTHREAD_SIG_RESTART SIGUSR1 #define PTHREAD_SIG_CANCEL SIGUSR2 /* DEFINICJE DANYCH, TYPÓW DANYCH ZDEFINJOWANYCH W INNYCH PLIKACH: */ /* Global array of thread handles, used for validating a thread id and retrieving the corresponding thread descriptor. Also used for mapping the available stack segments. */ extern struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX]; /* Descriptor of the initial thread */ extern struct _pthread_descr_struct __pthread_initial_thread; /* Descriptor of the manager thread */ extern struct _pthread_descr_struct __pthread_manager_thread; /* Descriptor of the main thread */ extern pthread_descr __pthread_main_thread; /* Limit between the stack of the initial thread (above) and the stacks of other threads (below). Aligned on a STACK_SIZE boundary. Initially 0, meaning that the current thread is (by definition) the initial thread. */ extern char * __pthread_initial_thread_bos; /* File descriptor for sending requests to the thread manager. Initially -1, meaning that pthread_initialize must be called. */ extern int __pthread_manager_request; /* Other end of the pipe for sending requests to the thread manager. */ extern int __pthread_manager_reader; /* Limits of the thread manager stack. */ extern char * __pthread_manager_thread_bos; extern char * __pthread_manager_thread_tos; /* Pending request for a process-wide exit */ extern int __pthread_exit_requested, __pthread_exit_code; /* Return the handle corresponding to a thread id */ static inline pthread_handle thread_handle(pthread_t id) { return &__pthread_handles[id % PTHREAD_THREADS_MAX]; } /* Validate a thread handle. Must have acquired h->h_spinlock before. */ /* Sprawdzenie poprawności otzrymanych danych o wątku */ static inline int invalid_handle(pthread_handle h, pthread_t id) { return h->h_descr == NULL || h->h_descr->p_tid != id; } /* Fill in defaults left unspecified by pt-machine.h. */ /* The page size we can get from the system. This should likely not be changed by the machine file, but you never know. */ #ifndef PAGE_SIZE #define PAGE_SIZE (sysconf(_SC_PAGE_SIZE)) #endif /* WYPE£NIENIE DANYCH ZALE¯NYCH OD SYSTEMU: wielkości strony pamięci, maksymalnego rozmiaru stosu itp. */ /* The max size of the thread stack segments. If the default THREAD_SELF implementation is used, this must be a power of two and a multiple of PAGE_SIZE. */ #ifndef STACK_SIZE #define STACK_SIZE (2 * 1024 * 1024) #endif /* The initial size of the thread stack. Must be a multiple of PAGE_SIZE. */ #ifndef INITIAL_STACK_SIZE #define INITIAL_STACK_SIZE (4 * PAGE_SIZE) #endif /* Size of the thread manager stack. The "- 32" avoids wasting space with some malloc() implementations. */ #ifndef THREAD_MANAGER_STACK_SIZE #define THREAD_MANAGER_STACK_SIZE (2 * PAGE_SIZE - 32) #endif /* The base of the "array" of thread stacks. The array will grow down from here. Defaults to the calculated bottom of the initial application stack. */ #ifndef THREAD_STACK_START_ADDRESS #define THREAD_STACK_START_ADDRESS __pthread_initial_thread_bos #endif /* Get some notion of the current stack. Need not be exactly the top of the stack, just something somewhere in the current frame. */ #ifndef CURRENT_STACK_FRAME #define CURRENT_STACK_FRAME ({ char __csf; &__csf; }) #endif /* Recover thread descriptor for the current thread */ /* Funkcja zwracająca wskażnik na wątek, który ją wywołał (jak this z C++) */ static inline pthread_descr thread_self (void) __attribute__((const)); static inline pthread_descr thread_self (void) { #ifdef THREAD_SELF THREAD_SELF #else char *sp = CURRENT_STACK_FRAME; if (sp >= __pthread_initial_thread_bos) return &__pthread_initial_thread; else if (sp >= __pthread_manager_thread_bos && sp < __pthread_manager_thread_tos) return &__pthread_manager_thread; else return (pthread_descr)(((unsigned long)sp | (STACK_SIZE-1))+1) - 1; #endif } /* Debugging */*/ #ifdef DEBUG #include <assert.h> #define ASSERT assert #define MSG __pthread_message #else #define ASSERT(x) #define MSG(msg,arg) #endif /* Internal global functions */ /* Prototypy funkcji z Linuxthreads */ void __pthread_destroy_specifics(void); void __pthread_perform_cleanup(void); void __pthread_sighandler(int sig); void __pthread_message(char * fmt, long arg); int __pthread_manager(void * reqfd); void __pthread_manager_sighandler(int sig); void __pthread_reset_main_thread(void); void __fresetlockfiles(void); /* System calls not declared in libc 5 */ /* Prototypy funkcji z libc5 */ int __clone(int (*child_function)(void *), void ** child_stack, int flags, void * arg); int __nanosleep(const struct timespec * rqtp, struct timespec * rmtp); int __sched_yield(void); int __sched_setparam(pid_t pid, const struct sched_param *param); int __sched_getparam(pid_t pid, struct sched_param *param); int __sched_setscheduler(pid_t pid, int policy, const struct sched_param *param); int __sched_getscheduler(pid_t pid); int __sched_get_priority_max(int policy); int __sched_get_priority_min(int policy); int __sched_rr_get_interval(pid_t pid, struct timespec *interval);