void _Region_Process_queue( Region_Control *the_region ) { Thread_Control *the_thread; void *the_segment; /* * Switch from using the memory allocation mutex to using a * dispatching disabled critical section. We have to do this * because this thread may unblock one or more threads that were * waiting on memory. * * NOTE: Be sure to disable dispatching before unlocking the mutex * since we do not want to open a window where a context * switch could occur. */ _Thread_Disable_dispatch(); _RTEMS_Unlock_allocator(); /* * NOTE: The following loop is O(n) where n is the number of * threads whose memory request is satisfied. */ for ( ; ; ) { the_thread = _Thread_queue_First( &the_region->Wait_queue ); if ( the_thread == NULL ) break; the_segment = (void **) _Region_Allocate_segment( the_region, the_thread->Wait.count ); if ( the_segment == NULL ) break; *(void **)the_thread->Wait.return_argument = the_segment; the_region->number_of_used_blocks += 1; _Thread_queue_Extract( &the_region->Wait_queue, the_thread ); the_thread->Wait.return_code = RTEMS_SUCCESSFUL; } _Thread_Enable_dispatch(); }
rtems_status_code rtems_region_get_segment( rtems_id id, uintptr_t size, rtems_option option_set, rtems_interval timeout, void **segment ) { rtems_status_code status; Region_Control *the_region; if ( segment == NULL ) { return RTEMS_INVALID_ADDRESS; } *segment = NULL; if ( size == 0 ) { return RTEMS_INVALID_SIZE; } the_region = _Region_Get_and_lock( id ); if ( the_region == NULL ) { return RTEMS_INVALID_ID; } if ( size > the_region->maximum_segment_size ) { status = RTEMS_INVALID_SIZE; } else { void *the_segment; the_segment = _Region_Allocate_segment( the_region, size ); if ( the_segment != NULL ) { *segment = the_segment; status = RTEMS_SUCCESSFUL; } else if ( _Options_Is_no_wait( option_set ) ) { status = RTEMS_UNSATISFIED; } else { Thread_queue_Context queue_context; Thread_Control *executing; _Thread_queue_Context_initialize( &queue_context ); _Thread_queue_Acquire( &the_region->Wait_queue, &queue_context ); executing = _Thread_Executing; executing->Wait.count = size; executing->Wait.return_argument = segment; /* FIXME: This is a home grown condition variable */ _Thread_queue_Context_set_thread_state( &queue_context, STATES_WAITING_FOR_SEGMENT ); _Thread_queue_Context_set_timeout_ticks( &queue_context, timeout ); _Thread_queue_Context_set_enqueue_callout( &queue_context, _Region_Enqueue_callout ); _Thread_queue_Enqueue( &the_region->Wait_queue.Queue, the_region->wait_operations, executing, &queue_context ); return _Status_Get_after_wait( executing ); } } _Region_Unlock( the_region ); return status; }
rtems_status_code rtems_region_get_segment( rtems_id id, uintptr_t size, rtems_option option_set, rtems_interval timeout, void **segment ) { Thread_Control *executing; Objects_Locations location; rtems_status_code return_status; Region_Control *the_region; void *the_segment; if ( !segment ) return RTEMS_INVALID_ADDRESS; *segment = NULL; if ( size == 0 ) return RTEMS_INVALID_SIZE; _RTEMS_Lock_allocator(); executing = _Thread_Get_executing(); the_region = _Region_Get( id, &location ); switch ( location ) { case OBJECTS_LOCAL: if ( size > the_region->maximum_segment_size ) return_status = RTEMS_INVALID_SIZE; else { _Region_Debug_Walk( the_region, 1 ); the_segment = _Region_Allocate_segment( the_region, size ); _Region_Debug_Walk( the_region, 2 ); if ( the_segment ) { the_region->number_of_used_blocks += 1; *segment = the_segment; return_status = RTEMS_SUCCESSFUL; } else if ( _Options_Is_no_wait( option_set ) ) { return_status = RTEMS_UNSATISFIED; } else { /* * Switch from using the memory allocation mutex to using a * dispatching disabled critical section. We have to do this * because this thread is going to block. */ /* FIXME: Lock order reversal */ _Thread_Disable_dispatch(); _RTEMS_Unlock_allocator(); executing->Wait.queue = &the_region->Wait_queue; executing->Wait.id = id; executing->Wait.count = size; executing->Wait.return_argument = segment; _Thread_queue_Enter_critical_section( &the_region->Wait_queue ); _Thread_queue_Enqueue( &the_region->Wait_queue, executing, timeout ); _Objects_Put( &the_region->Object ); return (rtems_status_code) executing->Wait.return_code; } } break; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* this error cannot be returned */ break; #endif case OBJECTS_ERROR: default: return_status = RTEMS_INVALID_ID; break; } _RTEMS_Unlock_allocator(); return return_status; }
rtems_status_code rtems_region_get_segment( Objects_Id id, uint32_t size, rtems_option option_set, rtems_interval timeout, void **segment ) { register Region_Control *the_region; Objects_Locations location; Thread_Control *executing; void *the_segment; if ( !segment ) return RTEMS_INVALID_ADDRESS; *segment = NULL; if ( size == 0 ) return RTEMS_INVALID_SIZE; _RTEMS_Lock_allocator(); executing = _Thread_Executing; the_region = _Region_Get( id, &location ); switch ( location ) { case OBJECTS_REMOTE: /* this error cannot be returned */ _RTEMS_Unlock_allocator(); return RTEMS_INTERNAL_ERROR; case OBJECTS_ERROR: _RTEMS_Unlock_allocator(); return RTEMS_INVALID_ID; case OBJECTS_LOCAL: if ( size > the_region->maximum_segment_size ) { _RTEMS_Unlock_allocator(); return RTEMS_INVALID_SIZE; } _Region_Debug_Walk( the_region, 1 ); the_segment = _Region_Allocate_segment( the_region, size ); _Region_Debug_Walk( the_region, 2 ); if ( the_segment ) { the_region->number_of_used_blocks += 1; _RTEMS_Unlock_allocator(); *segment = the_segment; return RTEMS_SUCCESSFUL; } if ( _Options_Is_no_wait( option_set ) ) { _RTEMS_Unlock_allocator(); return RTEMS_UNSATISFIED; } /* * Switch from using the memory allocation mutex to using a * dispatching disabled critical section. We have to do this * because this thread is going to block. */ _Thread_Disable_dispatch(); _RTEMS_Unlock_allocator(); executing->Wait.queue = &the_region->Wait_queue; executing->Wait.id = id; executing->Wait.count = size; executing->Wait.return_argument = segment; _Thread_queue_Enter_critical_section( &the_region->Wait_queue ); _Thread_queue_Enqueue( &the_region->Wait_queue, timeout ); _Thread_Enable_dispatch(); return (rtems_status_code) executing->Wait.return_code; } return RTEMS_INTERNAL_ERROR; /* unreached - only to remove warnings */ }