📄 memmgr.c copy
字号:
bool get_discarded_list; bool make_locked; uint alloc_id; uint user_alloc_id; uint offset; int discarded_list;} vmem_io_alloc;status_t vmem_ioctl_alloc( vmem_pool *pool, vmem_dev_info *dev, vmem_io_alloc *buffer ){ unsigned int client_id = buffer->client_id; vmem_client *client; vmem_entry *alloc; status_t result = B_OK; retry: ACQUIRE_BEN( pool->lock ); client = vmem_check_client_id( pool, buffer->client_id, dev ); if( client == NULL ) { result = B_BAD_VALUE; goto exit; } result = vmem_server_alloc( pool, client, buffer->size, &alloc ); if( result == B_BUSY ) { RELEASE_BEN( pool->lock ); goto retry; } if( buffer->make_locked ) alloc->alloc_user->prev = vmem_entry_LOCKED; if( buffer->get_discarded_list && (result == B_NO_MEMORY || result == B_OK) ) { buffer->discarded_list = client->discarded_list; client->discarded_list = INT_MAX; } if( result != B_OK ) goto exit; buffer->alloc_id = alloc->id; buffer->user_alloc_id = alloc->alloc_user - client->allocs; buffer->offset = alloc->pos << pool->block_shift; exit: RELEASE_BEN( pool->lock ); return result;}typedef struct vmem_io_free { uint client_id; uint alloc_id; bool get_discarded_list; int discarded_list;} vmem_io_free;status_t vmem_ioctl_free( vmem_pool *pool, vmem_dev_info *dev, vmem_io_free *buffer ){ uint client_id = buffer->client_id; uint alloc_id = buffer->alloc_id; vmem_client *client; vmem_entry *alloc; status_t result = B_OK; ACQUIRE_BEN( pool->lock ); client = vmem_check_client_id( pool, buffer->client_id, dev ); if( client == NULL ) { result = B_BAD_VALUE; goto exit; } if( alloc_id > pool->max_allocs ) { SHOW_ERROR( 1, "alloc_id=%d is invalid", alloc_id ); result = B_BAD_VALUE; goto exit; } alloc = &pool->allocs[alloc_id]; if( alloc->client != client ) { SHOW_ERROR( 1, "alloc_id %d doesn't belong to client %d", alloc_id, client ); result = B_BAD_VALUE; goto exit; } result = vmem_server_free( pool, client, alloc ); if( buffer->get_discarded_list && result == B_OK ) { buffer->discarded_list = client->discarded_list; client->discarded_list = INT_MAX; } exit: RELEASE_BEN( pool->lock ); return result;}static status_t vmem_client_create( vmem_pool *pool, const char *name, int max_allocs, vmem_client **res_client ){ int client_id; vmem_client *client; int i; free_entry *client_free_list = (free_entry *)pool->clients; status_t result = B_NO_MEMORY; client_id = pool->unused_clients - client_free_list; if( client_id == 0 ) { SHOW_ERROR0( 0, "Out of client ids" ); goto err1; } client = malloc( sizeof( *client )); if( client == NULL ) goto err2; client->id = client_id; max_allocs = min( max_allocs, 3 ); client->max_allocs = max_allocs; client->alloc_area_id = create_area( name, (void **)&client->user, B_ANY_ADDRESS, sizeof( vmem_user ) + max_allocs * sizeof( vmem_entry_user ), B_NO_LOCK, 0 ); if( client->alloc_area_id < 0 ) { result = client->alloc_area_id; goto err3; } client->allocs = (vmem_entry_user *)((int)client->user + sizeof( vmem_user *)); for( i = 0; i < max_allocs - 1; ++i ) client->allocs[i].next = i + 1; client->allocs[max_allocs - 1].next = INT_MAX; client->unused_list = 0; client->discarded_list = INT_MAX; pool->unused_clients = client_free_list[client_id].next; pool->clients[client_id] = client; *res_client = client; return B_OK; err3: free( client );err2:err1: return result;}typedef struct vmem_io_create { area_id alloc_area_id; uint client_id;} vmem_io_create;status_t vmem_ioctl_create( vmem_pool *pool, vmem_dev_info *dev, const char *name, vmem_io_create *buffer ){ status_t result; vmem_client *client; ACQUIRE_BEN( pool->lock ); result = vmem_client_create( pool, name, pool->max_allocs, &client ); if( result != B_OK ) goto exit; client->prev = NULL; client->next = dev->clients; if( dev->clients ) dev->clients->prev = client; dev->clients = client; buffer->client_id = client->id; buffer->alloc_area_id = client->alloc_area_id;exit: RELEASE_BEN( pool->lock ); return result;}static void vmem_server_free_client( vmem_pool *pool, vmem_client *client ){ vmem_entry *alloc; for( alloc = pool->first; alloc; alloc = alloc->next ) { if( alloc->client == client ) { vmem_server_discard( pool, alloc ); vmem_server_merge_allocs( pool, alloc, true ); } }}static void vmem_client_destroy( vmem_pool *pool, vmem_client *client ){ free_entry *client_free_list = (free_entry *)pool->clients; vmem_server_free_client( pool, client ); client_free_list[client->id].next = pool->unused_clients; pool->unused_clients = &client_free_list[client->id]; delete_area( client->alloc_area_id ); free( client );}typedef struct vmem_io_destroy { uint client_id;} vmem_io_destroy;status_t vmem_ioctl_destroy( vmem_pool *pool, vmem_dev_info *dev, vmem_io_destroy *buffer ){ uint client_id = buffer->client_id; status_t result; vmem_client *client; ACQUIRE_BEN( pool->lock ); client = vmem_check_client_id( pool, buffer->client_id, dev ); if( client == NULL ) { result = B_BAD_VALUE; goto exit; } if( client->prev ) client->prev->next = client->next; else dev->clients = client->next; if( client->next ) client->next->prev = client->prev; vmem_client_destroy( pool, client ); result = B_OK; exit: RELEASE_BEN( pool->lock ); return result;}void vmem_client_destroy_all( vmem_pool *pool, vmem_dev_info *dev ){ vmem_client *client, *next; for( client = dev->clients; client; client = next ) { next = client->next; vmem_client_destroy( pool, client ); }}vmem_pool *vmem_server_create( const char *name, int size, int block_size, int max_allocs, int max_clients ){ vmem_pool *pool; vmem_entry *first; int i; uint j; free_entry *clients_free_list; pool = malloc( sizeof( *pool )); if( pool == NULL ) goto err1; INIT_BEN( name, pool->lock ); if( pool->lock.sem < 0 ) goto err2; pool->max_clients = max_clients; pool->clients = malloc( sizeof( vmem_client * ) * max_clients ); if( pool->clients == NULL ) goto err3; memset( pool->clients, 0, sizeof( vmem_client * ) * max_clients ); clients_free_list = (free_entry *)pool->clients; // client_id 0 is unused (we use it as "end-of-freelist" ) for( i = 1; i < max_clients - 1; ++i ) clients_free_list[i].next = &clients_free_list[i+1]; clients_free_list[max_clients - 1].next = &clients_free_list[0]; pool->unused_clients = &clients_free_list[1]; pool->block_shift = minBits( block_size ); pool->block_size = 1 << pool->block_shift; pool->num_blocks = size >> pool->block_shift; max_allocs = max( max_allocs, 3 ); pool->max_allocs = max_allocs; pool->allocs = malloc( sizeof( vmem_entry ) * max_allocs ); if( pool->allocs == NULL ) goto err4; memset( pool->allocs, 0, sizeof( vmem_entry ) * max_allocs ); for( j = 0; j < pool->max_allocs; ++i ) pool->allocs[j].id = j; first = &pool->allocs[0]; first->next = NULL; first->prev = NULL; first->pos = 0; first->num_blocks = pool->num_blocks; first->alloc_user = &pool->alloc_dummy; first->client = NULL; pool->first = first; // dummy must look like an allocated, non-locked range // (this way find_vmem_block does not distinguish between // empty and allocated, non-locked range) pool->alloc_dummy.prev = 0; for( j = 1; j < pool->max_allocs - 1; ++i ) pool->allocs[j].next = &pool->allocs[j+1]; pool->allocs[pool->max_allocs - 1].next = NULL; pool->unused_list = &pool->allocs[1]; return pool; err4: free( pool->clients );err3: DELETE_BEN( pool->lock );err2: free( pool );err1: return NULL;}void vmem_server_destroy( vmem_pool *pool ){ free( pool->allocs ); free( pool->clients ); DELETE_BEN( pool->lock ); free( pool );}static vmem_client *vmem_check_client_id( vmem_pool *pool, uint client_id, vmem_dev_info *dev ){ vmem_client *client; if( client_id > pool->max_clients ) { SHOW_ERROR( 1, "client_id=%d is invalid (out of range)", client_id ); return NULL; } client = pool->clients[client_id]; if( (vmem_client **)client <= &pool->clients[0] || (vmem_client **)client >= &pool->clients[pool->max_clients] ) { SHOW_ERROR( 1, "client_id=%d is invalid (id is marked as being unused)", client_id ); return NULL; } if( client->dev != dev ) { SHOW_ERROR( 1, "client_id=%d doesn't belong to device handle", client_id ); return NULL; } return client;}void vmem_entry( vmem_user *pool, size_t size, int make_locked, vmem_user **alloc, void *addr, uint *alloc_id, uint *discarded_list ){ mem_io_alloc buffer; buffer->client_id = pool->client_id; buffer->size = size; buffer->get_discarded_list = discarded_list != NULL; buffer->make_locked = make_locked; result = pool->ioctl( pool->dev, pool->first_ioctl, buffer, sizeof( buffer )); if( result != B_OK ) return result; *alloc_id = buffer->alloc_id; *alloc = &pool->allocs[user_alloc_id]; *addr = pool->base_address + offset; if( discarded_list ) *discarded_list = buffer.discarded_list; return B_OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -