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).