1

我有一个任务的自定义分配,几乎完成了。不幸的是,我遇到了一个我似乎无法诊断的问题。分配由执行缓存分配(< 2kB)和区域分配(> 2kB)的两个函数处理。这是我的内存结构:

 23 typedef struct slab {
 24         void *addr;
 25         int bm[SLAB_SIZE/8/(8*sizeof(int))]; // bitmap for the slab
 26         struct slab *next;
 27 } slab;

 40 typedef struct {
 41         int alloc_unit;
 42         slab S;
 43 } cache;


 46 typedef struct { // structure for the entire memory
 47         cache C[9];
 48         region *R;
 49 } memory;

(注意:所有平板的位图大小相同,效率有点低,但我想让它首先像这样工作,而不是到处都有大量重复的代码)

问题在于相当复杂的 allocate_cache 函数,该函数适用于 8 字节以上的所有分配。我通过分配 50-100k 个 16B、32B、... 2kB 的实例对它进行了一些激烈的测试,一切正常。逻辑如下:每个都cache包含一个slab开头。每个都slab可以有SLAB_SIZE/alloc_unit slots,不同的slab不同(所以2kB的slab可以包含多达32个2kB内存的插槽,1kB的slab包含64个插槽,依此类推)。

这是我的分配缓存功能:

 55 void *allocate_cache(unsigned int size) { // cache allocation
 56
 57         // 1. Select the cache
 58         int ci = 0, si, pos, bmi; // cache_index, slot_index, position, bitmap index
 59         int slbn = 0; // slab number
 60         unsigned short check = 0;
 61         while ((size-1) >> (ci+3))
 62                 ci++;
 63         // 2. Find a slot
 64         bmi = 0; // bitmap index
 65         int lbmi = 0; // 'linked' bitmap index
 66         int counter = 0;
 67         int coefficient = SLAB_SIZE/M.C[ci].alloc_unit;
 68         do {
 69                 pos = find_zero_bit(M.C[ci].S.bm[bmi]); // Find the first zero bit in the bitmap
 70                 if (pos == -1) { bmi++; // If bm[bmi] does not have free slots, keep checking the map...
 71                         if(bmi == coefficient/(8*sizeof(int))){ // If bmi is max size, then we need to check
 72                                 slab *next_slab = &M.C[ci].S;            // the following slabs, if there are any.
 73                                 while(next_slab->next != NULL){ // While there are additional slabs
 74                                         next_slab = next_slab->next;
 75                                         slbn++; // Increment the slab counter.
 76                                         while(lbmi < bmi) { // Go through the slots in this slab too
 77                                                 pos = find_zero_bit(next_slab->bm[lbmi]); // Until a free slot has been found
 78                                                 if(pos != -1) { // If a free slot has been found...
 79                                                         set_bit(&(next_slab->bm[lbmi]), pos); // Mark it as occupied...
 80                                                         check = 1;
 81                                                         break;  // And break out of the loop.
 82                                                 }
 83                                         lbmi++; counter++;
 84                                         }
 85                                 if(check == 1) break; // If we already found a free slot in one of the slots, break.
 86                                 lbmi = 0;
 87                                 }
 88                         }
 89                 }
 90                 else break;
 91         } while(bmi < coefficient/(8*sizeof(int)));
 92         si = bmi*32 + counter*32 + (pos - 1);
 93         // compute the slot index based on bmi,  pos and counter
 94         // 3.a Slot not found => allocate a new slab
 95         printf("pos = %d , si = %d, bmi = %d, slbn = %d lbmi = %d counter = %d\n", pos, si, bmi, slbn, lbmi, counter); // sanity check
 96         if(pos == 32 && ((si+1) % coefficient == 0)) {
 97                 printf("===== SLAB FULL. NOW CREATING NEW SLAB. =====\n");
 98                 // Initialize a new slab.
 99                 slab *temp = &M.C[ci].S; // Set temp to the initially allocated slab
100                 while(temp->next != NULL) temp = temp->next; // Get the last currently allocated slab
101                 void *new_addr = mmap(NULL, SLAB_SIZE + sizeof(slab), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
102                 slab *new_slab = new_addr;
103                 new_slab->addr = (char *)new_addr + sizeof(slab);
104                 temp->next = new_slab; // Set the new slab as the one following the existing slabs
105                 temp->next->addr = new_slab->addr; // Set the new slab's address to the newly mmap'd address
106                 temp->next->next = NULL; // Set the new slab's NEXT pointer to NULL
107                 bzero(&new_slab->bm, SLAB_SIZE/M.C[ci].alloc_unit/8); // Zero-out the new slab's bitmap
108                 if(temp->addr == MAP_FAILED) { // Check if mmap succeeded...
109                         printf("mmap failed. Exiting...\n");
110                         exit(-1);
111                 }
112                 printf("Allocated memory for cache %d's slab %d  at address %p\n", ci, slbn, temp->next);
113         }
114         printf("Use cache %d , slab %d (allocation unit size: %d)\n", ci, slbn,M.C[ci].alloc_unit);
115         printf("Found slot %d in slab %d of cache %d\n", si % (SLAB_SIZE/M.C[ci].alloc_unit), slbn, ci);
116
117         // 3.b Slot found
118
119         if(M.C[ci].S.addr == NULL) { // Slab not allocated yet
120                 M.C[ci].S.addr = mmap(NULL, SLAB_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
121                 printf("Allocated memory for cache %d's slab at address %p\n", ci, M.C[ci].S.addr);
122         }
123
124         if(M.C[ci].S.addr == MAP_FAILED) {
125                 perror("mmap failed\n");
126                 exit(-1);
127         }
128         set_bit(&M.C[ci].S.bm[bmi], pos); // mark the bit as occupied
129
130         // 4. Return address
131
132         return M.C[ci].S.addr + si*M.C[ci].alloc_unit;
133 }

违规行似乎是line 77。运行 GDB 会给我以下结果:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400847 in allocate_cache (size=5) at allocator.c:77
77 pos = find_zero_bit(next_slab->bm[lbmi]); // Until a free slot has been found

但是,我不明白这是怎么回事。next_slab已正确初始化 ( line 101-111,并且 bm 是使用 bzero ( ) 清零的位图line 107。因此,我倾向于认为这是一个不同的问题,只是在第 107 行弹出,但我无法诊断它几天。

我也一直在检查我的逻辑,以确保我没有做任何愚蠢的事情,比如覆盖slab struct 地址,但据我所知,mmap 提供给我的范围不允许这种情况发生。

任何帮助或指示将不胜感激。

PS。如果您希望我以任何方式重新格式化代码,请告诉我。我意识到这可能有点难看。

编辑:一开始的缓存初始化是在我的init_memory()函数中完成的。与缓存相关的行如下:

161         // Init the caches
162         for(i =0; i<9; i++) {
163                 M.C[i].alloc_unit = 8<<i;
164                 M.C[i].S.addr = NULL;
165                 M.C[i].S.next = NULL;
166                 bzero(M.C[i].S.bm, SLAB_SIZE/M.C[i].alloc_unit/8);
167         }

更新:看来我发现了错误。这是一个逻辑错误,而不是其他任何事情。我的位图数组的大小为 256,即 0..255。在 8 字节分配的情况下,位图正确设置为 256,表示最后一个空闲槽已用完,但这与我的位图定义相冲突,因为 bm[2​​56] 是非法读取。因此,未定义的行为。我通过简单地将位图数组的大小增加 1 来解决这个问题,即int bm[((SLAB_SIZE/8)/(8*sizeof(int)))+1];.

非常感谢 Koushik,他帮助我解决了这个问题。他建议我在几个地方添加的括号可能也为我省去了一些调试方面的麻烦。

4

1 回答 1

1

问题:分段错误。

原因:指针未初始化。

地点和地点:

第 72 行:

slab *next_slab = &M.C[ci].S;

这里M.C[ci].S.next应该是NULL在进入

void *allocate_cache(unsigned int size)

取消引用在哪里完成?:

第 77 行:

pos = find_zero_bit(next_slab->bm[lbmi]); 

真实案例的原因:

while(next_slab->next != NULL)

未定义的行为。因为next_slab->next没有初始化。

另一个注意事项:

#define PAGE_SIZE 1024 better be #define PAGE_SIZE (1024)
#define SLAB_SIZE 16*PAGE_SIZE should be #define SLAB_SIZE (16*(PAGE_SIZE))

原因:第 67 行(还有其他地方)

int coefficient = SLAB_SIZE/M.C[ci].alloc_unit; is interpreted as
int coefficient = 16*1024/M.C[ci].alloc_unit;

这里乘法和除法具有相同的优先级。

于 2013-04-06T20:41:30.547 回答