The translation is temporarily closed for contributions due to maintenance, please come back later.


The locking is implemented to be per-subsystem because we do not expect a lot of contention on these. There are two locks: <literal>emul_lock</literal> used to protect manipulating of <literal>linux_emuldata</literal> and <literal>emul_shared_lock</literal> used to manipulate <literal>linux_emuldata_shared</literal>. The <literal>emul_lock</literal> is a nonsleepable blocking mutex while <literal>emul_shared_lock</literal> is a sleepable blocking <literal>sx_lock</literal>. Because ofDue to the per-subsystem locking we can coalesce some locks and that is why the em find offers the non-locking access.
(itstool) path: sect3/para
The locking is implemented to be per-subsystem because we do not expect a lot of contention on these. There are two locks: <literal>emul_lock</literal> used to protect manipulating of <literal>linux_emuldata</literal> and <literal>emul_shared_lock</literal> used to manipulate <literal>linux_emuldata_shared</literal>. The <literal>emul_lock</literal> is a nonsleepable blocking mutex while <literal>emul_shared_lock</literal> is a sleepable blocking <literal>sx_lock</literal>. Due to the per-subsystem locking we can coalesce some locks and that is why the em find offers the non-locking access.
Context English Portuguese (Brazil) State
struct linux_emuldata_shared {

int refs;

pid_t group_pid;

LIST_HEAD(, linux_emuldata) threads; /* head of list of linux threads */
struct linux_emuldata_shared {

int refs;

pid_t group_pid;

LIST_HEAD(, linux_emuldata) threads; /* head of list of linux threads */
The <varname>refs</varname> is a reference counter being used to determine when we can free the structure to avoid memory leaks. The <varname>group_pid</varname> is to identify PID ( = TGID) of the whole process ( = thread group). The <varname>threads</varname> pointer is the head of the list of threads in the process. O <varname>refs</varname> é um contador de referência sendo usado para determinar quando podemos liberar a estrutura para evitar vazamentos de memória. O <varname>group_pid</varname> é para identificar o PID (=TGID) de todo o processo (=grupo de threads). O ponteiro <varname>threads</varname> é o cabeçalho da lista de threading no processo.
The <literal>linux_emuldata</literal> structure can be obtained from the process using <function>em_find</function>. The prototype of the function is: A estrutura <literal>linux_emuldata</literal> pode ser obtida a partir do processo usando <function>em_find</function>. O protótipo da função é:
struct linux_emuldata *em_find(struct proc *, int locked); struct linux_emuldata * em_find (struct proc *, int bloqueado);
Here, <varname>proc</varname> is the process we want the emuldata structure from and the locked parameter determines whether we want to lock or not. The accepted values are <literal>EMUL_DOLOCK</literal> and <literal>EMUL_DOUNLOCK</literal>. More about locking later. Aqui, <varname>proc</varname> é o processo em que queremos a estrutura emuldata e o parâmetro locked determina se queremos ou não bloquear. Os valores aceitos são <literal>EMUL_DOLOCK</literal> e <literal>EMUL_DOUNLOCK</literal>. Mais sobre o bloqueio mais tarde.
PID mangling Maqueando PID
As there is a difference in view as what to the idea of a process ID and thread ID is between FreeBSD and <trademark class="registered">Linux</trademark> we have to translate the view somehow. We do it by PID mangling. This means that we fake what a PID (=TGID) and TID (=PID) is between kernel and userland. The rule of thumb is that in kernel (in Linuxulator) PID = PID and TGID = shared -&gt; group pid and to userland we present <literal>PID = shared -&gt; group_pid</literal> and <literal>TID = proc -&gt; p_pid</literal>. The PID member of <literal>linux_emuldata structure</literal> is a FreeBSD PID. Por causa da visão diferente descrita sabendo o que é um ID de processo e ID de thread entre o FreeBSD e o <trademark class="registered">Linux</trademark> nós temos que traduzir a view de alguma forma. Nós fazemos isso pelo manuseio do PID. Isto significa que nós falsificamos o que um PID (=TGID) e um TID (=PID) é entre o kernel e o userland. A regra é que no kernel (no Linuxulator) PID=PID e TGID=grupo de id -&gt; compartilhado e para userland nós apresentamos <literal>PID=shared -&gt; group_pid </literal> e <literal>TID=proc -&gt; p_pid</literal>. O membro PID da estrutura <literal>linux_emuldata </literal> é um PID do FreeBSD.
The above affects mainly getpid, getppid, gettid syscalls. Where we use PID/TGID respectively. In copyout of TIDs in <function>child_clear_tid</function> and <function>child_set_tid</function> we copy out FreeBSD PID. O acima afeta principalmente syscalls getyscl, getppid, gettid. Onde usamos PID/TGID, respectivamente. Em cópia de TIDs em <function>child_clear_tid</function> e <function>child_set_tid</function> copiamos o PID FreeBSD.
Clone syscall syscall Clone
The <function>clone</function> syscall is the way threads are created in <trademark class="registered">Linux</trademark>. The syscall prototype looks like this: A syscall <function>clone</function> é o modo como as threads são criadas no <trademark class="registered">Linux</trademark>. O protótipo syscall é assim:
int linux_clone(l_int flags, void *stack, void *parent_tidptr, int dummy,
void * child_tidptr);
int linux_clone(l_int flags, void *stack, void *parent_tidptr, int dummy,
void * child_tidptr);
The <varname>flags</varname> parameter tells the syscall how exactly the processes should be cloned. As described above, <trademark class="registered">Linux</trademark> can create processes sharing various things independently, for example two processes can share file descriptors but not VM, etc. Last byte of the <varname>flags</varname> parameter is the exit signal of the newly created process. The <varname>stack</varname> parameter if non-<literal>NULL</literal> tells, where the thread stack is and if it is <literal>NULL</literal> we are supposed to copy-on-write the calling process stack (i.e. do what normal <citerefentry><refentrytitle>fork</refentrytitle><manvolnum>2</manvolnum></citerefentry> routine does). The <varname>parent_tidptr</varname> parameter is used as an address for copying out process PID (i.e. thread id) once the process is sufficiently instantiated but is not runnable yet. The <varname>dummy</varname> parameter is here because of the very strange calling convention of this syscall on i386. It uses the registers directly and does not let the compiler do it what results in the need of a dummy syscall. The <varname>child_tidptr</varname> parameter is used as an address for copying out PID once the process has finished forking and when the process exits. O parâmetro <varname>flags</varname> informa a syscall como exatamente os processos devem ser clonados. Como descrito acima, o <trademark class="registered">Linux</trademark> pode criar processos compartilhando várias coisas independentemente, por exemplo, dois processos podem compartilhar file descriptors, mas não VM, etc. Ultimo byte do parametro <varname>flags</varname> é o sinal de saída do processo recém-criado. O parâmetro <varname>stack</varname> se não <literal>NULL</literal> diz, onde está a pilha de threading e se é <literal>NULL</literal> nós devemos copiar-na-escrita chamando a pilha de processos (isto é, faz a rotina normal de <citerefentry><refentrytitle>fork</refentrytitle><manvolnum>2</manvolnum></citerefentry>). O parâmetro <varname>parent_tidptr</varname> é usado como um endereço para copiar o PID do processo (ou seja, o id do thread), uma vez que o processo esteja suficientemente instanciado, mas ainda não seja executável. O parâmetro <varname>dummy</varname> está aqui devido à convenção de chamada muito estranha desta syscall em i386. Ele usa os registradores diretamente e não deixa o compilador fazer o que resulta na necessidade de uma syscall falsa. O parâmetro <varname>child_tidptr</varname> é usado como um endereço para copiar o PID assim que o processo terminar de bifurcar e quando o processo terminar.
The syscall itself proceeds by setting corresponding flags depending on the flags passed in. For example, <literal>CLONE_VM</literal> maps to RFMEM (sharing of VM), etc. The only nit here is <literal>CLONE_FS</literal> and <literal>CLONE_FILES</literal> because FreeBSD does not allow setting this separately so we fake it by not setting RFFDG (copying of fd table and other fs information) if either of these is defined. This does not cause any problems, because those flags are always set together. After setting the flags the process is forked using the internal <function>fork1</function> routine, the process is instrumented not to be put on a run queue, i.e. not to be set runnable. After the forking is done we possibly reparent the newly created process to emulate <literal>CLONE_PARENT</literal> semantics. Next part is creating the emulation data. Threads in <trademark class="registered">Linux</trademark> does not signal their parents so we set exit signal to be 0 to disable this. After that setting of <varname>child_set_tid</varname> and <varname>child_clear_tid</varname> is performed enabling the functionality later in the code. At this point we copy out the PID to the address specified by <varname>parent_tidptr</varname>. The setting of process stack is done by simply rewriting thread frame <varname>%esp</varname> register (<varname>%rsp</varname> on amd64). Next part is setting up TLS for the newly created process. After this <citerefentry><refentrytitle>vfork</refentrytitle><manvolnum>2</manvolnum></citerefentry> semantics might be emulated and finally the newly created process is put on a run queue and copying out its PID to the parent process via <function>clone</function> return value is done. O syscall prossegue definindo flags correspondentes dependendo dos flags passadas. Por exemplo, mapas <literal>CLONE_VM</literal> para RFMEM (compartilhamento de VM), etc. O único nit aqui é <literal>CLONE_FS</literal> e <literal>CLONE_FILES</literal> porque o FreeBSD não permite configurar isso separadamente, então nós o falsificamos não configurando RFFDG (copiando a tabela fd e outras informações fs) se qualquer uma delas estiver definida. Isso não causa nenhum problema, porque essas flags são sempre definidas juntas. Depois de definir as flags, o processo é bifurcado usando a rotina <function>fork1</function> interna, o processo é instrumentado para não ser colocado em uma fila de execução, ou seja, não deve ser definido como executável. Depois que a bifurcação é feita, possivelmente reparamos o processo recém-criado para emular a semântica <literal>CLONE_PARENT</literal>. A próxima parte está criando os dados de emulação. Threads no <trademark class="registered">Linux</trademark> não sinalizam seus processos pais, então nós definimos o sinal de saída como 0 para desabilitar isso. Depois que a configuração de <varname>child_set_tid</varname> e <varname>child_clear_tid</varname> é executada, habilitando a funcionalidade posteriormente no código. Neste ponto, copiamos o PID para o endereço especificado por <varname>parent_tidptr</varname>. A configuração da pilha de processos é feita simplesmente reescrevendo o registro do quadro de linha <varname>% esp</varname> (<varname>% rsp</varname> no amd64). A próxima parte é configurar o TLS para o processo recém-criado. Depois disso, a semântica <citerefentry><refentrytitle>vfork</refentrytitle><manvolnum>2</manvolnum></citerefentry> pode ser emulada e, finalmente, o processo recém-criado é colocado em uma fila de execução e copiando seu PID para o processo pai através do valor de retorno <function>clone</function> é feito.
The <function>clone</function> syscall is able and in fact is used for emulating classic <citerefentry><refentrytitle>fork</refentrytitle><manvolnum>2</manvolnum></citerefentry> and <citerefentry><refentrytitle>vfork</refentrytitle><manvolnum>2</manvolnum></citerefentry> syscalls. Newer glibc in a case of 2.6 kernel uses <function>clone</function> to implement <citerefentry><refentrytitle>fork</refentrytitle><manvolnum>2</manvolnum></citerefentry> and <citerefentry><refentrytitle>vfork</refentrytitle><manvolnum>2</manvolnum></citerefentry> syscalls. A syscall <function>clone</function> é capaz e de fato é usado para emulação de syscalls <citerefentry><refentrytitle>fork</refentrytitle><manvolnum></manvolnum></citerefentry> e <citerefentry><refentrytitle>vfork</refentrytitle><manvolnum>2</manvolnum></citerefentry>. O glibc mais novo em um caso de kernel 2.6 usa o <function>clone</function> para implementar syscalls <citerefentry><refentrytitle>fork</refentrytitle><manvolnum>2</manvolnum></citerefentry> e <citerefentry><refentrytitle>vfork</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
Locking Bloqueio
The locking is implemented to be per-subsystem because we do not expect a lot of contention on these. There are two locks: <literal>emul_lock</literal> used to protect manipulating of <literal>linux_emuldata</literal> and <literal>emul_shared_lock</literal> used to manipulate <literal>linux_emuldata_shared</literal>. The <literal>emul_lock</literal> is a nonsleepable blocking mutex while <literal>emul_shared_lock</literal> is a sleepable blocking <literal>sx_lock</literal>. Due to the per-subsystem locking we can coalesce some locks and that is why the em find offers the non-locking access. O bloqueio é implementado como per-subsystem porque não esperamos muita disputa sobre eles. Existem dois bloqueios: <literal>emul_lock</literal> usado para proteger a manipulação de <literal>linux_emuldata</literal> e <literal>emul_shared_lock</literal> usado para manipular <literal>linux_emuldata_shared</literal>. O <literal>emul_lock</literal> é um mutex bloqueador não tolerável, enquanto <literal>emul_shared_lock</literal> é um bloqueio travável <literal>sx_lock</literal>. Devido ao bloqueio por subsistema, podemos unir alguns bloqueios e é por isso que o em-find oferece o acesso sem bloqueio.
This section deals with TLS also known as thread local storage. Esta seção trata do TLS também conhecido como armazenamento local de thread.
Introduction to threading Introdução ao threading
Threads in computer science are entities within a process that can be scheduled independently from each other. The threads in the process share process wide data (file descriptors, etc.) but also have their own stack for their own data. Sometimes there is a need for process-wide data specific to a given thread. Imagine a name of the thread in execution or something like that. The traditional <trademark class="registered">UNIX</trademark> threading API, <application>pthreads</application> provides a way to do it via <citerefentry><refentrytitle>pthread_key_create</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>pthread_setspecific</refentrytitle><manvolnum>3</manvolnum></citerefentry> and <citerefentry><refentrytitle>pthread_getspecific</refentrytitle><manvolnum>3</manvolnum></citerefentry> where a thread can create a key to the thread local data and using <citerefentry><refentrytitle>pthread_getspecific</refentrytitle><manvolnum>3</manvolnum></citerefentry> or <citerefentry><refentrytitle>pthread_getspecific</refentrytitle><manvolnum>3</manvolnum></citerefentry> to manipulate those data. You can easily see that this is not the most comfortable way this could be accomplished. So various producers of C/C++ compilers introduced a better way. They defined a new modifier keyword thread that specifies that a variable is thread specific. A new method of accessing such variables was developed as well (at least on i386). The <application>pthreads</application> method tends to be implemented in userspace as a trivial lookup table. The performance of such a solution is not very good. So the new method uses (on i386) segment registers to address a segment, where TLS area is stored so the actual accessing of a thread variable is just appending the segment register to the address thus addressing via it. The segment registers are usually <varname>%gs</varname> and <varname>%fs</varname> acting like segment selectors. Every thread has its own area where the thread local data are stored and the segment must be loaded on every context switch. This method is very fast and used almost exclusively in the whole i386 <trademark class="registered">UNIX</trademark> world. Both FreeBSD and <trademark class="registered">Linux</trademark> implement this approach and it yields very good results. The only drawback is the need to reload the segment on every context switch which can slowdown context switches. FreeBSD tries to avoid this overhead by using only 1 segment descriptor for this while <trademark class="registered">Linux</trademark> uses 3. Interesting thing is that almost nothing uses more than 1 descriptor (only <application>Wine</application> seems to use 2) so <trademark class="registered">Linux</trademark> pays this unnecessary price for context switches. Threads na ciência da computação são entidades com um processo que podem ser agendados independentemente de qualquer outro. As threads nos processos compartilham amplos dados de processos (file descriptors, etc.) mas também tem sua prŕopria pilha para seus próprios dados. Algumas vezes é preciso para um processamento amplo de dados dado uma thread. Imagine um nome de uma thread algo assim. A tradicional API de threading do <trademark class="registered">UNIX</trademark>, <application>pthreads</application> prove um caminho para isso em <citerefentry><refentrytitle>pthread_key_create</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>pthread_setspecific</refentrytitle><manvolnum>3</manvolnum></citerefentry> and <citerefentry><refentrytitle>pthread_getspecific</refentrytitle><manvolnum>3</manvolnum></citerefentry> onde a thread pode criar uma chave para os dados da thread local <citerefentry><refentrytitle>pthread_getspecific</refentrytitle><manvolnum>3</manvolnum></citerefentry> ou <citerefentry><refentrytitle>pthread_getspecific</refentrytitle><manvolnum>3</manvolnum></citerefentry> para manipular esses dados. Você pode ver que esse não é o caminho mais confortavel que poderia ser usado. Então varios produtores de compiladores C/C++ introduziram um caminho melhor. Eles definiram uma nova chave modificadora de thread que especifica que a variavel é especifica de uma thread. Um novo método de acessar as variaveis foi desenvolvio como (ao menos no i386). O método <application>pthreads</application> tende a ser implementado no espaço de usuário como uma tabela de lookup trivial. A performance como uma solução não é muito boa. Então o novo método (no i386) registradores de segmentos para endereçar um segmento, onde a área do TLS é armazenada, então o atual acesso da variável de uma thread é apenas adicionada ao registrador de segmentos para o endereçamento via it. Os registradores de segmentos são usualmente <varname>%gs</varname> e <varname>%fs</varname> agindo como seletores de segmento. Toda thread tem sua própria área onde os dados da thread local são armazenados e o segmento deve ser carregado em toda troca de contexto. Esse método é muito rapido e usado em todo mundo em volta do <trademark class="registered">UNIX</trademark> i386. Ambos FreeBSD e <trademark class="registered">Linux</trademark> Implementam sua abordagem e seus resultados tem sido muito bons. Unico ponto negativo é ter que recarregar o segmento em toda troca de contexto que pode deixar o processo lento. FreeBSD tenta evitar essa sobrecarga usando apenas 1 descritor de segmento enquanto <trademark class="registered">Linux</trademark> usa 3. Interessante que isso quase nunca usa mais que 1 descritor (apenas o <application>Wine</application> parece usar 2) então o <trademark class="registered">Linux</trademark> paga esse preço desnecessário na troca de contexto.
Segments on i386 Segmentos em i386
The i386 architecture implements the so called segments. A segment is a description of an area of memory. The base address (bottom) of the memory area, the end of it (ceiling), type, protection, etc. The memory described by a segment can be accessed using segment selector registers (<varname>%cs</varname>, <varname>%ds</varname>, <varname>%ss</varname>, <varname>%es</varname>, <varname>%fs</varname>, <varname>%gs</varname>). For example let us suppose we have a segment which base address is 0x1234 and length and this code: A arquitetura i386 implementa os então chamados segmentos.Um segmento é uma descrição de um espaço na memória. A base de endereço (baixa) na area da memória, o fim disso (teto), tipo, proteção, etc. A memória descrita por um segmento pode ser acessada usando um seletor de segmento (<varname>%cs</varname>, <varname>%ds</varname>, <varname>%ss</varname>, <varname>%es</varname>, <varname>%fs</varname>, <varname>%gs</varname>). Por exemplo, deixe nos supor que temos um segmento com base no endereço 0x1234 e comprimento e esse codigo:
mov %edx,%gs:0x10 mov %edx,%gs:0x10
This will load the content of the <varname>%edx</varname> register into memory location 0x1244. Some segment registers have a special use, for example <varname>%cs</varname> is used for code segment and <varname>%ss</varname> is used for stack segment but <varname>%fs</varname> and <varname>%gs</varname> are generally unused. Segments are either stored in a global GDT table or in a local LDT table. LDT is accessed via an entry in the GDT. The LDT can store more types of segments. LDT can be per process. Both tables define up to 8191 entries. Isso carregará o conteúdo do registro <varname>% edx</varname> na localização da memória 0x1244. Alguns registradores de segmento têm um uso especial, por exemplo <varname>% cs</varname> é usado para segmento de código e <varname>% ss</varname> é usado para o segmento de pilha, mas <varname>% fs</varname> e <varname>% gs</varname> geralmente não são usados. Os segmentos são armazenados em uma tabela GDT global ou em uma tabela LDT local. O LDT é acessado por meio de uma entrada no GDT. O LDT pode armazenar mais tipos de segmentos. LDT pode ser por processo. Ambas as tabelas definem até 8191 entradas.
Implementation on <trademark class="registered">Linux</trademark> i386 Implementação no <trademark class="registered">Linux</trademark> i386
There are two main ways of setting up TLS in <trademark class="registered">Linux</trademark>. It can be set when cloning a process using the <function>clone</function> syscall or it can call <function>set_thread_area</function>. When a process passes <literal>CLONE_SETTLS</literal> flag to <function>clone</function>, the kernel expects the memory pointed to by the <varname>%esi</varname> register a <trademark class="registered">Linux</trademark> user space representation of a segment, which gets translated to the machine representation of a segment and loaded into a GDT slot. The GDT slot can be specified with a number or -1 can be used meaning that the system itself should choose the first free slot. In practice, the vast majority of programs use only one TLS entry and does not care about the number of the entry. We exploit this in the emulation and in fact depend on it. Existem duas maneiras principais de configurar o TLS no <trademark class="registered">Linux</trademark>. Pode ser definido ao clonar um processo usando a syscall <function>clone</function> ou ele pode chamar <function>set_thread_area</function>. Quando um processo passa a flag <literal>CLONE_SETTLS</literal> para <function>clone</function>, o kernel espera que a memória apontada pelo registrador <varname>% esi</varname> uma representação <trademark class = "registered">Linux</trademark> do espaço do usuário de um segmento, que é traduzido para a representação da máquina de um segmento e carregado em um slot GDT. O slot GDT pode ser especificado com um número ou -1 pode ser usado, o que significa que o próprio sistema deve escolher o primeiro slot livre. Na prática, a grande maioria dos programas usa apenas uma entrada de TLS e não se importa com o número da entrada. Nós exploramos isso na emulação e dependemos disso.
Emulation of <trademark class="registered">Linux</trademark> TLS Emulação de TLS do <trademark class="registered">Linux</trademark>
i386 i386
Loading of TLS for the current thread happens by calling <function>set_thread_area</function> while loading TLS for a second process in <function>clone</function> is done in the separate block in <function>clone</function>. Those two functions are very similar. The only difference being the actual loading of the GDT segment, which happens on the next context switch for the newly created process while <function>set_thread_area</function> must load this directly. The code basically does this. It copies the <trademark class="registered">Linux</trademark> form segment descriptor from the userland. The code checks for the number of the descriptor but because this differs between FreeBSD and <trademark class="registered">Linux</trademark> we fake it a little. We only support indexes of 6, 3 and -1. The 6 is genuine <trademark class="registered">Linux</trademark> number, 3 is genuine FreeBSD one and -1 means autoselection. Then we set the descriptor number to constant 3 and copy out this to the userspace. We rely on the userspace process using the number from the descriptor but this works most of the time (have never seen a case where this did not work) as the userspace process typically passes in 1. Then we convert the descriptor from the <trademark class="registered">Linux</trademark> form to a machine dependant form (i.e. operating system independent form) and copy this to the FreeBSD defined segment descriptor. Finally we can load it. We assign the descriptor to threads PCB (process control block) and load the <varname>%gs</varname> segment using <function>load_gs</function>. This loading must be done in a critical section so that nothing can interrupt us. The <literal>CLONE_SETTLS</literal> case works exactly like this just the loading using <function>load_gs</function> is not performed. The segment used for this (segment number 3) is shared for this use between FreeBSD processes and <trademark class="registered">Linux</trademark> processes so the <trademark class="registered">Linux</trademark> emulation layer does not add any overhead over plain FreeBSD. O carregamento de TLS para o segmento atual acontece chamando <function>set_thread_area</function> enquanto o TLS é carregado para um segundo processo em <function>clone</function> é feito no bloco separado em <function>clone</function>. Essas duas funções são muito semelhantes. A única diferença é o carregamento real do segmento GDT, que acontece na próxima troca de contexto para o processo recém-criado, enquanto <function>set_thread_area</function> deve carregar isso diretamente. O código basicamente faz isso. Ele copia o descritor de segmento de formulário <trademark class="registered">Linux</trademark> da área de usuário. O código verifica o número do descritor, mas como isso difere entre o FreeBSD e o <trademark class="registered">Linux</trademark>, maquiamos um pouco. Nós suportamos apenas índices de 6, 3 e -1. O número 6 é genuíno do <trademark class="registered">Linux</trademark>, 3 é genuíno do FreeBSD one e -1 significa uma auto seleção. Em seguida, definimos o número do descritor como constante 3 e copiamos isso para o espaço do usuário. Contamos com o processo em espaço de usuário usando o número do descritor, mas isso funciona na maior parte do tempo (nunca vi um caso em que isso não funcionou), como o processo em espaço de usuário normalmente passa em 1. Então, convertemos o descritor da classe do <trademark class="registered">Linux</trademark> para um formulário dependente da máquina (isto é, independente do sistema operacional) e copie isto para o descritor de segmento definido pelo FreeBSD. Finalmente podemos carregá-lo. Atribuímos o descritor às threads PCB (bloco de controle de processo) e carregamos o segmento <varname>% gs</varname> usando <function>load_gs</function>. Este carregamento deve ser feito em uma seção crítica para que nada possa nos interromper. O caso <literal>CLONE_SETTLS</literal> funciona exatamente como este, apenas o carregamento usando <function>load_gs</function> não é executado. O segmento usado para isso (segmento número 3) é compartilhado para este uso entre os processos do FreeBSD e do <trademark class="registered">Linux</trademark> para que a camada de emulação <trademark class="registered">Linux</trademark> não adicione nenhuma sobrecarga sobre o FreeBSD.
amd64 amd64
The amd64 implementation is similar to the i386 one but there was initially no 32bit segment descriptor used for this purpose (hence not even native 32bit TLS users worked) so we had to add such a segment and implement its loading on every context switch (when a flag signaling use of 32bit is set). Apart from this the TLS loading is exactly the same just the segment numbers are different and the descriptor format and the loading differs slightly. A implementação do amd64 é semelhante à do i386, mas inicialmente não havia um descritor de segmento de 32 bits usado para esse propósito (por isso nem usuários nativos de TLB de 32 bits trabalhavam), então tivemos que adicionar esse segmento e implementar seu carregamento em cada troca de contexto (quando a flag sinalizando uso de 32 bits está definida). Além disso, o carregamento de TLS é exatamente o mesmo, apenas os números de segmento são diferentes e o formato do descritor e o carregamento diferem ligeiramente.


User avatar None

Source string changed

FreeBSD Doc / articles_linux-emulationPortuguese (Brazil)

The locking is implemented to be per-subsystem because we do not expect a lot of contention on these. There are two locks: <literal>emul_lock</literal> used to protect manipulating of <literal>linux_emuldata</literal> and <literal>emul_shared_lock</literal> used to manipulate <literal>linux_emuldata_shared</literal>. The <literal>emul_lock</literal> is a nonsleepable blocking mutex while <literal>emul_shared_lock</literal> is a sleepable blocking <literal>sx_lock</literal>. Because ofDue to the per-subsystem locking we can coalesce some locks and that is why the em find offers the non-locking access.
a month ago
Browse all component changes


English Portuguese (Brazil)
No related strings found in the glossary.

Source information

Source string comment
(itstool) path: sect3/para
Source string location
String age
a month ago
Source string age
a month ago
Translation file
articles/pt_BR/linux-emulation.po, string 270