Entendendo uma chamada do sistema XINU - getstk.c [closed]

0

Estou tendo problemas para conceitualmente entender o que está acontecendo no final desta chamada de sistema e por quê. Eu entendo que o método getstk.c retorna o maior endereço de memória do espaço disponível, mas não entende o que parte do código está fazendo. Alguma clareza sobre isso seria ótimo. As áreas de código que não entendo completamente são enfatizadas em asteriscos.

/* getstk.c - getstk */

#include <xinu.h>

/*------------------------------------------------------------------------
 *  getstk  -  Allocate stack memory, returning highest word address
 *------------------------------------------------------------------------
 */
char    *getstk(
          uint32        nbytes          /* size of memory requested     */
        )
{
        intmask mask;                   /* saved interrupt mask         */
        struct  memblk  *prev, *curr;   /* walk through memory list     */
        struct  memblk  *fits, *fitsprev; /* record block that fits     */

        mask = disable();
        if (nbytes == 0) {
                restore(mask);
                return (char *)SYSERR;
        }

        nbytes = (uint32) roundmb(nbytes);      /* use mblock multiples */

        prev = &memlist;
        curr = memlist.mnext;
        fits = NULL;
        fitsprev = NULL;  /* to avoid a compiler warning */

        while (curr != NULL) {                  /* scan entire list     */
                if (curr->mlength >= nbytes) {  /* record block address */
                        fits = curr;            /*   when request fits  */
                        fitsprev = prev;
                }
                prev = curr;
                curr = curr->mnext;
        }

        if (fits == NULL) {                     /* no block was found   */
                restore(mask);
                return (char *)SYSERR;
        }
        if (nbytes == fits->mlength) {          /* block is exact match */
                fitsprev->mnext = fits->mnext;
        **} else {                                /* remove top section   */
                fits->mlength -= nbytes;
                fits = (struct memblk *)((uint32)fits + fits->mlength);
        }**
        memlist.mlength -= nbytes;
        restore(mask);
        **return (char *)((uint32) fits + nbytes - sizeof(uint32));**
}

O struct memblk pode ser encontrado aqui:

struct  memblk  {           /* see roundmb & truncmb    */
    struct  memblk  *mnext;     /* ptr to next free memory blk  */
    uint32  mlength;        /* size of blk (includes memblk)*/
    };
extern  struct  memblk  memlist;    /* head of free memory list */

Por que eles estão retornando os ajustes + nbytes - sizeof (uint32)? Por que eles estão lançando ajustes (uma estrutura) para digitar uint32?

    
por kamran619 27.04.2013 / 08:59

1 resposta

1

Estes são os dois cenários em que um bloco de tamanho suficiente foi encontrado. Observe que no primeiro caso, estamos removendo um nó inteiro ( fits ) de memlist vinculando o próximo ponteiro do nó anterior ao próximo ponteiro desse nó. Este bloco é então usado no valor de retorno, então eu presumo disso e dos comentários, etc. que a intenção aqui é encontrar alguma memória livre em um conjunto e removê-lo do conjunto livre para uso.

    if (nbytes == fits->mlength) {          /* block is exact match */
            fitsprev->mnext = fits->mnext;
    **} else {                                /* remove top section   */
            fits->mlength -= nbytes;
            fits = (struct memblk *)((uint32)fits + fits->mlength);
    }**

Agora, no segundo caso que você destaca, o bloco encontrado é maior que o suficiente . É importante que essa coisa toda não seja retornada porque o excesso será desperdiçado e, além disso, a natureza do valor de retorno (veja abaixo) implica que o receptor não terá registro do tamanho real, o que pode significar se este bloco for recuperado. mais tarde, ele só poderia ser recuperado com base no tamanho solicitado (o valor original do parâmetro nbytes ), impedindo o excesso desperdiçado permanentemente no conjunto de memes.

Para lidar com isso, o bloco fits é encurtado para o tamanho do restante . Ou seja, não o tamanho do bloco solicitado , mas o valor que sobrará quando o valor solicitado for subtraído do comprimento do bloco encontrado (mais do que suficiente). Ao contrário da primeira cláusula do if / else, o bloco de ajustes aqui é não removido do conjunto. É apenas encurtado:

 fits->mlength -= nbytes;

Em seguida, o ponteiro, que será usado no valor de retorno, é movido para a frente até o final do bloco recém-encurtado. Isso aponta para a região que será removida do pool:

 fits = (struct memblk *)((uint32)fits + fits->mlength);

Observe que, embora o ponteiro fits tenha sido movido, o código não se preocupa em corrigir fits->mlength para o tamanho da região fits agora aponta para (o que não é o mesmo de onde estava na linha anterior ). Isto é porque o que é retornado não é uma struct . Eu acho que essa função é chamada de algum lugar que não usa struct memblk . Em outras palavras, struct memblk é usado neste código, mas não no chamador . Portanto, você pode considerar getstk() como uma chamada de API pública, em que struct memblk não faz parte da API pública - é apenas parte da mecânica interna.

O valor de retorno é apenas um ponteiro de char, para o topo (ponto mais alto) de uma região de memória.

getstk  -  Allocate stack memory, returning highest word address

Presumivelmente, o chamador vai assumir que o ponteiro retornou pontos para o topo de uma região nbytes em tamanho. Isso é muito semelhante ao que malloc () faz, por exemplo:

char *dataA = malloc(4096);
char *dataB = getstk(4096);

Só que o malloc retorna um endereço na parte inferior de um bloco de 4096 bytes, então os endereços vão de dataA a dataA + 4095 . Como getstk () retorna o endereço alto, o intervalo será de dataB - 4095 a dataB (na verdade, não é bem assim, já que "tamanho da palavra" está sendo usado, continue lendo).

Assim:

    return (char *)((uint32) fits + nbytes - sizeof(uint32));

Esta é a região nbytes long que fits aponta atualmente para a parte inferior (o que normalmente consideramos o endereço inicial , como com malloc). Mas getstk () deve retornar o endereço mais alto - mais precisamente o endereço de mais alta palavra . Uma "palavra" é geralmente 4 bytes / 32 bits; aqui está explicitamente sizeof(uint32) . Assim, o endereço retornado aponta para os últimos 4 bytes em um bloco nbytes em tamanho (na verdade, nbytes foi arredondado via roundmb (), mas presumivelmente esse sistema também é usado na recuperação).

    
por 27.04.2013 / 14:50