Beispiel #1
0
int FF_Controller::Is_Unit_Busy(
	FF_Controller_Context *p_controller_context)
{	
 	// Check to see if the unit_index is busy.
	// For the HBC, only one device can be accessed at one time.
	U32 unit_index = p_controller_context->m_flash_address.Unit_Index();
	if (m_can_units_overlap)
	{
		// Check this unit to see if it's busy.
 		if (m_p_controller_context[unit_index] != 0)
 		{
	 		TRACEF(TRACE_L5, 
				(EOL "Unit is busy, unit_index = %d", p_controller_context->m_flash_address.Unit_Index()));
 		
 			// It is busy, so the context must wait.
			m_p_flash->m_stats.Inc_Num_Waits_Unit(unit_index);

 			// Put this context on the wait list for the unit_index.
			LIST_INSERT_TAIL(&m_context_list_wait_unit[unit_index], 
	    		&p_controller_context->m_list);
						
			return 1;
		
 		} // unit_index is busy
 		
	}
	else
	{
		// Check to see if any unit is busy.
		U32 num_units = Flash_Address::Num_Units();
		for (U32 any_unit_index = 0; any_unit_index < num_units; any_unit_index++)
		{
 			if (m_p_controller_context[any_unit_index] != 0)
 			{
	 			TRACEF(TRACE_L5, 
					(EOL "Unit is busy, any_unit_index = %d", p_controller_context->m_flash_address.Unit_Index()));
 			
 				// A unit is busy, so the context must wait.
				m_p_flash->m_stats.Inc_Num_Waits_Unit(unit_index);

 				// Put this context on the wait list for the unit_index.
				LIST_INSERT_TAIL(&m_context_list_wait_unit[unit_index], 
	    			&p_controller_context->m_list);
							
				return 1;
			
 			} // unit_index is busy
		}
		// Continue if no unit is busy.
	}

	// Unit is not busy.
	// Save the pointer to the callback context that will be run
	// when the command finished.
	// The caller will start the command.

	m_p_controller_context[unit_index] = p_controller_context;
	return 0;

} // Is_Unit_Busy
Beispiel #2
0
int FF_Controller::Is_Buss_Busy(
	FF_Controller_Context *p_controller_context)
{	
 	// Check to see if the controller is busy.
 	if (m_buss_context)
 	{
	 	TRACEF(TRACE_L5, 
			(EOL "Buss is busy, unit_index = %d", p_controller_context->m_flash_address.Unit_Index()));
 	
		m_p_flash->m_stats.Inc_Num_Waits_Buss();

 		// It is busy, so the context must wait.
 		// Put this context on the wait list for the controller.
	    LIST_INSERT_TAIL(&m_context_list_wait_buss, 
	    	&p_controller_context->m_list);
		
		return 1;
	
 	} // controller is busy
 	
	// Save pointer to context that owns the buss.
	m_buss_context = p_controller_context;
	return 0;

} // Is_Buss_Busy
Beispiel #3
0
int mcl_list_insert_tail(void *data, mcl_list *list_ptr)
{
	if (list_ptr->_list_sz >= MCL_LIST_MAX_SIZE) {
		fprintf(stderr, "list [%p] size beyond max size [%d]", list_ptr, MCL_LIST_MAX_SIZE);
		return 0;
	}

	mcl_list_node *node = (mcl_list_node *)malloc(sizeof(*node));

	node->_data = data;
	LIST_INSERT_TAIL(&node->_entry, &list_ptr->_entries);
	++ list_ptr->_list_sz;

	return 1;
}
Beispiel #4
0
/**
 * proposer_decree_request - Helper function for proposers to decree requests.
 */
static int
proposer_decree_request(struct paxos_request *req)
{
  struct paxos_instance *inst;

  // Allocate an instance and copy in the value from the request.
  inst = g_malloc0(sizeof(*inst));
  memcpy(&inst->pi_val, &req->pr_val, sizeof(req->pr_val));

  // Send a decree if we're not preparing; if we are, defer it.
  if (pax->prep != NULL) {
    LIST_INSERT_TAIL(&pax->idefer, inst, pi_le);
    return 0;
  } else {
    return proposer_decree(inst);
  }
}
Beispiel #5
0
void ke_list_insert_tail(enum ke_list_enum list, struct ctx_t *ctx)
{
	assert(!ke_list_member(list, ctx));
	switch (list) {
	case ke_list_context: LIST_INSERT_TAIL(context, ctx); break;
	case ke_list_running: LIST_INSERT_TAIL(running, ctx); break;
	case ke_list_finished: LIST_INSERT_TAIL(finished, ctx); break;
	case ke_list_zombie: LIST_INSERT_TAIL(zombie, ctx); break;
	case ke_list_suspended: LIST_INSERT_TAIL(suspended, ctx); break;
	case ke_list_alloc: LIST_INSERT_TAIL(alloc, ctx); break;
	}
}
Beispiel #6
0
void CM_Frame_Table::Inc_Replaceable_Pages(LIST *p_list_waiting_contexts)
{
 	TRACE_ENTRY(CM_Frame_Table::Inc_Replaceable_Pages);

	// Increment number of replaceable pages.
	m_num_pages_replaceable++;
	CT_ASSERT((m_num_pages_replaceable <= m_num_page_frames), CM_Frame_Table::Inc_Replaceable_Pages);
	m_p_stats->Set_Num_Pages_Replaceable(m_num_pages_replaceable);

	// See if any context is waiting for a frame.
	if (LIST_IS_EMPTY(&m_list_wait_frame))
		return;

	// There is a context waiting for a page frame.
	// Remove it from the list and put it on the ready list.
	Callback_Context *p_callback_context = 
		(Callback_Context *)LIST_REMOVE_TAIL(&m_list_wait_frame);
	m_p_stats->Dec_Num_Waits_For_Page_Frame();

	LIST_INSERT_TAIL(p_list_waiting_contexts, &p_callback_context->m_list);

}  // CM_Frame_Table::Inc_Replaceable_Pages
Beispiel #7
0
CM_Frame_Table * CM_Frame_Table::Allocate(
		CM_Mem					*p_mem, 
		CM_CONFIG				*p_config, 
		CM_PREFETCH_CALLBACK	*p_prefetch_callback,
		CM_WRITE_CALLBACK		*p_write_callback,
		CM_Stats				*p_stats,
		void					*p_callback_context,
		U32						 num_page_frames,
		void					*p_page_memory)
{
	// Allocate CM_Frame_Table object
	CM_Frame_Table *p_frame_table = 
		(CM_Frame_Table *)p_mem->Allocate(sizeof(CM_Frame_Table));

	if (p_frame_table == 0)
		return 0;
	
	// Initialize table lists.
	LIST_INITIALIZE(&p_frame_table->m_list_waiting_to_flush);
	LIST_INITIALIZE(&p_frame_table->m_list_wait_frame);

	// Initialize each of our dummy frames.  Each of our frame lists
	// is a dummy frame so that, when the last frame in the list points
	// to the head of the list, we can treat it as a frame without
	// having to check to see if we are pointing to the head of the list.
	p_frame_table->m_clock_list.Initialize(0, CM_PAGE_STATE_CLEAN);
	p_frame_table->m_dirty_clock_list.Initialize(0, CM_PAGE_STATE_DIRTY);

	// Save callbacks.
	p_frame_table->m_p_prefetch_callback = p_prefetch_callback;
	p_frame_table->m_p_write_callback = p_write_callback;
	p_frame_table->m_p_callback_context = p_callback_context;

	// Make sure the page size is a multiple of 8 for alignment.
	p_frame_table->m_page_size = ((p_config->page_size + 7) / 8) * 8;

	p_frame_table->m_num_pages_replaceable = 0;
	p_frame_table->m_num_pages_clock = 0;
	p_frame_table->m_num_pages_dirty_clock = 0;
	p_frame_table->m_num_pages_being_written = 0;
	p_frame_table->m_num_pages_working_set = 0;
	p_frame_table->m_p_clock_frame = 0;
	p_frame_table->m_p_dirty_clock_frame = 0;

	// Find out how much memory is available.
	// Leave this for debugging.  Should be close to zero.
	U32 memory_available = p_mem->Memory_Available();

	// Save number of page frames.
	p_frame_table->m_num_page_frames = num_page_frames;

    if (p_config->page_table_size)
	{
		// Linear mapping
		// Don't allocate more pages than specified in the config.
		if (p_frame_table->m_num_page_frames > p_config->page_table_size)
			p_frame_table->m_num_page_frames = p_config->page_table_size;
	}

	// Allocate array of page frames
	p_frame_table->m_p_page_frame_array = (char *)p_page_memory;

	// Allocate array of frames
	p_frame_table->m_p_frame_array = 
		(CM_Frame *)p_mem->Allocate(sizeof(CM_Frame) * p_frame_table->m_num_page_frames);
	if (p_frame_table->m_p_frame_array == 0)
		return 0;

	// When m_p_clock_frame is zero, we know that the frame table is not yet initialized.
	p_frame_table->m_p_clock_frame = 0;

	// Initialize each frame
    CM_Frame *p_frame;
	for (U32 index = 0; index < p_frame_table->m_num_page_frames; index++)
	{
		// Point to the next frame.
		p_frame = p_frame_table->Get_Frame(index + 1);

		// Have the frame initialize itself.
		p_frame->Initialize(index + 1, CM_PAGE_STATE_CLEAN);
		CT_ASSERT((p_frame_table->Get_Frame(index + 1) == p_frame), CM_Frame_Table::Allocate);
		CT_ASSERT((p_frame->Get_Frame_Index() == (index + 1)), CM_Frame_Table::Allocate);

		// Make sure the list object is first in the frame.
		CT_ASSERT(((CM_Frame *)&p_frame->m_list == p_frame), CM_Frame_Table::Allocate);
		CT_ASSERT((p_frame->Is_Replaceable()), CM_Frame_Table::Allocate);

		// Initially, each frame is on the clock list
		LIST_INSERT_TAIL(&p_frame_table->m_clock_list.m_list, &p_frame->m_list);
		p_frame_table->m_num_pages_clock++;
		p_frame_table->m_num_pages_replaceable++;
	}

	// Initialize the clocks
	p_frame_table->m_p_clock_frame = p_frame;
	p_frame_table->m_p_dirty_clock_frame = &p_frame_table->m_dirty_clock_list;

	// Calculate dirty page writeback threshold from the percentage in the config file.
	p_frame_table->m_dirty_page_writeback_threshold = 
		(p_frame_table->m_num_page_frames * p_config->dirty_page_writeback_threshold)
		/ 100;

	// Calculate dirty page error threshold from the percentage in the config file.
	p_frame_table->m_dirty_page_error_threshold = (p_frame_table->m_num_page_frames 
		* p_config->dirty_page_error_threshold)
		/ 100;

	// Make sure the number of reserve pages is less than the number of pages in the cache.
	// This would only happen in a test environment where the cache size is small.
	p_frame_table->m_num_reserve_pages = p_config->num_reserve_pages;
	if (p_frame_table->m_num_reserve_pages > p_frame_table->m_num_pages_replaceable)

		// Make number of reserve pages less than number of pages in the cache.
		p_frame_table->m_num_reserve_pages = 
			p_frame_table->m_num_pages_replaceable - (p_frame_table->m_num_pages_replaceable / 2);

	// Calculate the maximum number of dirty pages.
	U32 max_number_dirty_pages = p_frame_table->m_num_pages_replaceable
		- p_frame_table->m_num_reserve_pages;

	// Make sure the dirty page error threshold is less than the maximum number of dirty pages;
	// otherwise we will have a context waiting for a page to be cleaned, and it will 
	// never happen.  This would only occur in a test situation, where cache size is small.
	if (p_frame_table->m_dirty_page_error_threshold > max_number_dirty_pages)

		// Make dirty page error threshold less than max_number_dirty_pages.
		p_frame_table->m_dirty_page_error_threshold = 
			max_number_dirty_pages - (max_number_dirty_pages / 2);

	// Make sure the writeback threshold is less than the dirty page error threshold.
	if (p_frame_table->m_dirty_page_writeback_threshold > p_frame_table->m_dirty_page_error_threshold)

		// Make dirty page writeback threshold less than dirty page error threshold.
		p_frame_table->m_dirty_page_writeback_threshold = 
			p_frame_table->m_dirty_page_error_threshold 
				- (p_frame_table->m_dirty_page_error_threshold / 2);

	// Initialize pointer to statistics object
	p_frame_table->m_p_stats = p_stats;

#ifdef _WINDOWS

	// Initialize Windows mutex
	p_frame_table->m_mutex = CreateMutex(
		NULL, // LPSECURITY_ATTRIBUTES lpEventAttributes,	// pointer to security attributes
		
		// If TRUE, the calling thread requests immediate ownership of the mutex object. 
		// Otherwise, the mutex is not owned. 
		0, // flag for initial ownership 
		// If lpName is NULL, the event object is created without a name. 
		NULL // LPCTSTR lpName 	// pointer to semaphore-object name  
	   );

	if (p_frame_table->m_mutex == 0)
	{
		DWORD erc = GetLastError();
		CT_Log_Error(CT_ERROR_TYPE_FATAL,
			"CM_Frame_Table::Allocate", 
			"CreateMutex failed",
			erc,
			0);
		return p_frame_table;
	}
#else
#ifdef THREADX
	// Initialize Threadx semaphore
	Status	status = tx_semaphore_create(&p_frame_table->m_mutex, "CmMutex",
		1); // initial count
#else
	// Initialize Nucleus semaphore
	Status	status = NU_Create_Semaphore(&p_frame_table->m_mutex, "CmMutex",
		1, // initial count
		NU_FIFO);
#endif

	if (status != OK)
	{
		CT_Log_Error(CT_ERROR_TYPE_FATAL,
			"CM_Frame_Table::Allocate", 
			"NU_Create_Semaphore failed",
			status,
			0);
		return p_frame_table;
	}
#endif

#ifdef _DEBUG
	Got_Mutex = 0;
#endif

	// Return pointer to table object
	return p_frame_table;

} // CM_Frame_Table::Allocate
Beispiel #8
0
Status CM_Frame::Open_Page(
	U32 flags,
	Callback_Context *p_callback_context,	
	CM_PAGE_HANDLE *p_page_handle,
    CM_STATE_CHANGE *p_state_change,
	CM_Stats *p_stats)
{
    Status status = OK;

    // Determine page state before open
    int previous_lock = Is_Page_Locked();

	switch (CM_OPEN_MODE(flags))
	{
	case CM_OPEN_MODE_REMAP:

		// A page opened for remap is locked remap and closed dirty
		TRACE_NUMBER_EOL(TRACE_L5, "CM_Frame::Open_Page mode remap, page = ", (U32)m_page_number);

		// See if page is locked for write.
		if ((m_write_lock == 0) && (m_writeback_lock == 0))
		{
			// The page has no write locks, so we can open it for remap.
			if (m_num_remap_locks == 0)

				// This is the first time the page is locked for remap.
				// Tell the stats record how many pages are locked for remap.
				p_stats->Inc_Num_Pages_Locked_Remap();

			// Lock page for remap
			m_num_remap_locks++;

			// Return page handle
			*p_page_handle = CM_Frame_Handle::Create_Page_Handle(flags, Get_Frame_Index());
			goto Return_State_Change;
		}

		// The page is locked for write or writeback.
		// Did the user specify CM_CALLBACK_IF_LOCKED?
		if (flags & CM_CALLBACK_IF_LOCKED)
		{
			// Queue this context.
			LIST_INSERT_TAIL(&m_list_wait_for_unlock, &p_callback_context->m_list);
			if (m_write_lock)
				p_stats->Inc_Num_Waits_For_Write_Lock();
			else
				p_stats->Inc_Num_Waits_For_Writeback_Lock();
		}

		TRACE_NUMBER_EOL(TRACE_L5, "CM_Frame::Open_Page mode remap CM_ERROR_PAGE_LOCKED, page = ", (U32)m_page_number);
		status = CM_ERROR_PAGE_LOCKED;
        goto Return_State_Change;

	case CM_OPEN_MODE_READ:
		// A page opened for read is locked read and closed clean.
		TRACE_NUMBER_EOL(TRACE_L5, "CM_Frame::Open_Page mode read, page = ", (U32)m_page_number);

		// See if page is locked for write.
		// It's OK if the page is locked for remap.
		if (m_write_lock == 0)
		{
			if (m_num_read_locks == 0)

				// This is the first time the page is locked.
				// Tell the stats record how many pages are locked for read.
				p_stats->Inc_Num_Pages_Locked_Read();

			// Lock page for read
			m_num_read_locks++;

			// Return page handle
			*p_page_handle = CM_Frame_Handle::Create_Page_Handle(flags, Get_Frame_Index());
			goto Return_State_Change;
		}

		// The page is locked for write.
		// Did the user specify CM_CALLBACK_IF_LOCKED?
		if (flags & CM_CALLBACK_IF_LOCKED)
		{
			// Queue this context.
			LIST_INSERT_TAIL(&m_list_wait_for_unlock, &p_callback_context->m_list);
			p_stats->Inc_Num_Waits_For_Write_Lock();
		}

		TRACE_NUMBER_EOL(TRACE_L5, "CM_Frame::Open_Page mode read CM_ERROR_PAGE_LOCKED, page = ", (U32)m_page_number);
		status = CM_ERROR_PAGE_LOCKED;
        goto Return_State_Change;

	case CM_OPEN_MODE_WRITE:
	case CM_OPEN_MODE_WRITE_THROUGH:
		// A page opened for write is locked write and closed dirty
		TRACE_NUMBER_EOL(TRACE_L5, "CM_Frame::Open_Page mode write, page = ", (U32)m_page_number);

		if ((m_write_lock == 0) && (m_num_remap_locks == 0) && (m_num_read_locks == 0)

			// Note that the page must not be locked for write if the page is already
			// locked for writeback.  If the page is being written, a verify may also be
			// required.  The verify will fail if the page is overwritten before it
			// is verified.
			&& (m_writeback_lock == 0) )
		{
			// The page is not locked.
			// Lock the page for write
			m_write_lock = 1;

			// Tell the stats record how many pages are locked for write.
			p_stats->Inc_Num_Pages_Locked_Write();

			// Return page handle
			*p_page_handle = CM_Frame_Handle::Create_Page_Handle(flags, Get_Frame_Index());
			goto Return_State_Change;
		}

		// The page is locked.
		// Did the user specify CM_CALLBACK_IF_LOCKED?
		if (flags & CM_CALLBACK_IF_LOCKED)
		{
			// Queue this context.
			LIST_INSERT_TAIL(&m_list_wait_for_unlock, &p_callback_context->m_list);
			if (m_write_lock)
				p_stats->Inc_Num_Waits_For_Write_Lock();
			else if (m_num_read_locks)
				p_stats->Inc_Num_Waits_For_Read_Lock();
			else
				p_stats->Inc_Num_Waits_For_Writeback_Lock();
		}

		TRACE_NUMBER_EOL(TRACE_L5, "CM_Frame::Open_Page mode write CM_ERROR_PAGE_LOCKED, page = ", (U32)m_page_number);
		status = CM_ERROR_PAGE_LOCKED;
        goto Return_State_Change;

	default:
        status = CM_ERROR(INVALID_MODE);
		break;
	} // switch

Return_State_Change:

    if (previous_lock || Is_Page_Dirty())

        // The page was previously locked or dirty.
        *p_state_change = CM_STATE_NO_CHANGE;

    else 

        // The page was not previously locked or dirty, and we just
        // opened it, so the page just became unreplaceable.
        *p_state_change = CM_JUST_BECAME_UNREPLACEABLE;
    
	return status;

} // CM_Frame::Open_Page
Beispiel #9
0
Status CM_Frame_Table::Open_Page( 
	U32 frame_index,
	U32 flags,
	Callback_Context *p_callback_context,
	void **pp_page_frame,
	CM_PAGE_HANDLE *p_page_handle)
{
	TRACE_ENTRY(CM_Frame_Table::Open_Page);

	// This page is present in the cache.
	// Given the index, point to the frame for this page.
	CM_Frame *p_frame = Get_Frame(frame_index);
	CT_ASSERT((p_frame->Get_Page_Number() != -1), CM_Frame_Table::Open_Page);

	// Check to see if this would exceed the maximum number of dirty pages.
	if (CM_OPEN_MODE(flags) == CM_OPEN_MODE_WRITE)
	{
		// Is the frame already dirty?
		if (!p_frame->Is_Page_Dirty())
		{
			// The page frame is clean now.
			if (Check_For_Max_Dirty_Pages() != OK)
			{
				// There are too many dirty pages.
				// Does user want to wait for a page frame?
				if (flags & CM_CALLBACK_IF_NO_FRAME)
				{
					// Context will be scheduled again when we have a
					// replaceable page frame.
					LIST_INSERT_TAIL(&m_list_wait_frame, &p_callback_context->m_list); 
					m_p_stats->Inc_Num_Waits_For_Page_Frame();
				}
				TRACE_NUMBER_EOL(TRACE_L5, "CM_Frame_Table::Open_Page CM_ERROR_MAX_DIRTY_PAGES, page = ", 0);
				return CM_ERROR(MAX_DIRTY_PAGES);
			}
		}
	}

	// Ask the frame to open itself.
    // Get back any change in page state.
    CM_STATE_CHANGE state_change;
	Status status = p_frame->Open_Page(flags, p_callback_context, 
        p_page_handle, &state_change, m_p_stats);

    switch (state_change)
    {
    case CM_JUST_BECAME_UNREPLACEABLE:

        // Update the number of replaceable pages in the clock.
		Dec_Replaceable_Pages();
        break;

    default:
        break;
    }

	if (status == OK)
	{
		// Return pointer to page frame
		*pp_page_frame = Get_Page_Frame(frame_index);
		return OK;
	}

	// Return CM_ERROR_PAGE_LOCKED if page locked; context is queued
	// if user specified CM_CALLBACK_IF_LOCKED.
	if (status == CM_ERROR_PAGE_LOCKED)
		m_p_stats->Inc_Num_Error_Page_Locked();

	// Return null pointer to page frame
	*pp_page_frame = 0;
	return status;

} // CM_Frame_Table::Open_Page
Beispiel #10
0
void CM_Frame_Table::Flush_Next(void *p_context, Status status)
{
	TRACE_ENTRY(CM_Frame_Table::Flush_Next);

	CM_Cache_Context *p_cache_context = (CM_Cache_Context *)p_context;
	CM_Frame_Table *p_frame_table = p_cache_context->m_p_frame_table;
	CM_Cache *p_cache = (CM_Cache *)p_cache_context->m_cache_handle;

	p_cache->Obtain_Mutex();

	// Check to see if there are any dirty pages
	if ((p_frame_table->m_num_pages_dirty_clock 
		+ p_frame_table->m_num_pages_being_written) == 0)
	{
		// We have flushed the last page.
		if (p_cache_context->m_destroy)
			p_cache->Release_Resources();

		p_cache->Release_Mutex();

		// When we terminate this context, the parent context will be
		// scheduled to run.
		p_cache_context->Terminate(p_cache_context, p_cache_context->Get_Status());
		return;
	}

	// There are more dirty pages that need to be flushed.
	while (p_frame_table->m_num_pages_dirty_clock)
	{
		// Call user's callback to write a dirty page.
		Status status = p_frame_table->Write_Dirty_Page(p_cache_context->m_cache_handle);

		if (status != OK)
			// The user was not able to create another context to write
			// a dirty page.  We will try again when a writeback is closed.
			// Exit the while loop.
			break;
	}

	// Check again to see if there are any dirty pages. Write_Dirty_Page above released
	// the mutex.  At this time, the dirty pages could have been closed.
	if ((p_frame_table->m_num_pages_dirty_clock 
		+ p_frame_table->m_num_pages_being_written) == 0)
	{
		// We have flushed the last page.
		if (p_cache_context->m_destroy)
			p_cache->Release_Resources();

		p_cache->Release_Mutex();

		// When we terminate this context, the parent context will be
		// scheduled to run.
		p_cache_context->Terminate(p_cache_context, p_cache_context->Get_Status());
		return;
	}

	// There are still dirty pages to be flushed.
	// Queue this context on the list of contexts waiting for a page to be unlocked.
	// We will run again the next time a page opened for writeback is closed.
	LIST_INSERT_TAIL(&p_frame_table->m_list_waiting_to_flush, &p_cache_context->m_list);
	p_frame_table->m_p_stats->Inc_Num_Flush_Waits_For_Lock();
	p_cache->Release_Mutex();



} // CM_Frame_Table::Flush_Next