Esempio n. 1
0
    void remove_unused_entities_from(EntityCollection& entities)
    {
        typedef typename EntityCollection::value_type EntityType;

        vector<EntityType*> to_remove;

        for (auto& entity : entities)
        {
            if (!is_referenced(entity))
            {
                RENDERER_LOG_DEBUG("entity " FMT_ENTITY " is not referenced and will be removed.",
                    entity.get_path().c_str(),
                    entity.get_uid());

                to_remove.push_back(&entity);
                remove_unreferenced_entity(entity);
            }
        }

        for (EntityType* entity : to_remove)
        {
            RENDERER_LOG_DEBUG("removing entity " FMT_ENTITY "...",
                entity->get_path().c_str(),
                entity->get_uid());

            entities.remove(entity);
        }
    }
Esempio n. 2
0
File: swapper.c Progetto: gz/aos10
/**
 * This function will select a page (based on second chance)
 * and swap it out to file system. However if the selected page
 * was not dirty then we just need to mark it swapped again and
 * can return immediatly.
 * We stop the initiator thread as long as we're swapping
 * data out to the file system. The thread is restarted in the
 * write callback function (above).
 *
 * @param initiator ID of the thread who caused the swapping to happen
 * @return	SWAPPING_PENDING in case we need to write the page to the disk
 * 			SWAPPING_COMPLETE in case the page was not dirty
 * 			OUT_OF_SWAP_SPACE if our swap space is already full
 * 			NO_PAGE_AVAILABLE if second_chance_select did not find a page
 */
int swap_out(L4_ThreadId_t initiator) {
	page_queue_item* page = second_chance_select(&active_pages_head);
	if(page == NULL) {
		return NO_PAGE_AVAILABLE;
	}
	assert(!is_referenced(page));

	// decide where in the swap file our page will be
	if(page->swap_offset < 0 && (page->swap_offset = allocate_swap_entry()) < 0)
		return OUT_OF_SWAP_SPACE;

	dprintf(1, "swap_out: Second chance selected page: thread:0x%X vaddr:0x%X swap_offset:0x%X\n", page->tid, page->virtual_address, page->swap_offset);

	if(is_dirty(page)) {
		dprintf(1, "Selected page is dirty, need to write to swap space\n");

		page->to_swap = PAGESIZE;
		page->initiator = initiator;
		TAILQ_INSERT_TAIL(&swapping_pages_head, page, entries);

		file_table_entry* swap_fd = get_process(root_thread_g)->filetable[SWAP_FD];
		assert(swap_fd != NULL);

		data_ptr physical_page = pager_physical_lookup(page->tid, page->virtual_address);
		assert(physical_page != NULL);

		// write page in swap file
		assert(PAGESIZE % BATCH_SIZE == 0);
		for(int write_offset=0; write_offset < page->to_swap; write_offset += BATCH_SIZE) {
			nfs_write(
				&swap_fd->file->nfs_handle,
				page->swap_offset + write_offset,
				BATCH_SIZE,
				physical_page + write_offset,
				&swap_write_callback,
				(int)page
			);
		}

		return SWAPPING_PENDING;
	}
	else {
		assert(page->swap_offset >= 0);
		page_table_entry* pte = pager_table_lookup(page->tid, page->virtual_address);
		frame_free(CLEAR_LOWER_BITS(pte->address));
		mark_swapped(pte, page->swap_offset);
		free(page);

		return SWAPPING_COMPLETE;
	}

}
Esempio n. 3
0
    void remove_unreferenced_entity(Entity& entity)
    {
        assert(!is_referenced(entity));

        for (auto& referenced_entity : m_outgoing_refs[&entity])
        {
            // Remove references from referenced entities toward this entity.
            IncomingRefVec& incoming_refs = m_incoming_refs[referenced_entity.m_entity];
            erase_if(
                incoming_refs,
                [&entity](const IncomingRef& ref) { return ref.m_entity == &entity; });
            if (incoming_refs.empty())
                m_incoming_refs.erase(referenced_entity.m_entity);

            if (!is_referenced(*referenced_entity.m_entity))
            {
                RENDERER_LOG_DEBUG("entity " FMT_ENTITY " is not referenced and will be removed.",
                    referenced_entity.m_entity->get_path().c_str(),
                    referenced_entity.m_entity->get_uid());

                remove_unreferenced_entity(*referenced_entity.m_entity);

                RENDERER_LOG_DEBUG("removing entity " FMT_ENTITY "...",
                    referenced_entity.m_entity->get_path().c_str(),
                    referenced_entity.m_entity->get_uid());

                assert(referenced_entity.m_map || referenced_entity.m_vector);
                if (referenced_entity.m_map != nullptr)
                    referenced_entity.m_map->remove(referenced_entity.m_entity);
                else referenced_entity.m_vector->remove(referenced_entity.m_entity);
            }
        }

        // Remove references from this entity toward other entities.
        m_outgoing_refs.erase(&entity);
    }
Esempio n. 4
0
bool RegisterAllocator::has_free(int count,
                                 Assembler::Register* next_table,
                                 Assembler::Register next, bool spill) {
  const Register current = next;
  do {
    next = next_table[next];
    // Check to see whether or not the register is available for allocation.
    if (!is_referenced(next) && (spill || !is_mapping_something(next))) {
      count--;
      if (count == 0) return true;
    }
  } while(next != current);
  // Couldn't allocate a register without spilling.
  return false;
}
Esempio n. 5
0
Assembler::Register RegisterAllocator::spill(Assembler::Register* next_table, Assembler::Register& next) {
  // Use a round-robin strategy to spill the registers.
  const Register current = next;
  do {
    next = next_table[next];
    // Check to see whether or not the register is available for spilling.
    if (!is_referenced(next)) {
      // Spill the register.
      spill(next);
      // Return the register.
      return next;
    }
  } while(next != current);
  // Couldn't allocate a register without spilling.
  return Assembler::no_reg;
}
Esempio n. 6
0
Assembler::Register RegisterAllocator::allocate(Assembler::Register reg) {
  // For now we allow registers that aren't handled by the register allocator
  // to be allocated. This might seem a bit strange.
  if (reg < (Assembler::Register)Assembler::number_of_registers) {
    GUARANTEE(!is_referenced(reg), "Cannot allocate referenced register");
    // Setup a reference to the newly allocated register.
    reference(reg);
    // Spill the register.
    spill(reg);

    //cse
    wipe_notation_of(reg);
  }
  // Return the register.
  return reg;
}
Esempio n. 7
0
File: swapper.c Progetto: gz/aos10
/**
 * Second chance select implementation for choosing pages to
 * swap out. This will loop through the queue and find the
 * oldest unreferenced page.
 * Note: Since we use software emulated reference bits, in case
 * everything is mapped in the HW page table this degenerates
 * to pure FIFO.
 *
 * @param page_queue
 * @return oldest unreferenced page (removed from the queue)
 */
static page_queue_item* second_chance_select(struct pages_head* page_queue) {

	page_queue_item* page;

	// do a second chance search for a page over all currently active pages
    for(page = page_queue->tqh_first; page != NULL; page = page_queue->tqh_first) {

    	if(is_referenced(page)) {
    		TAILQ_REMOVE(page_queue, page, entries); // remove oldest page
    		dereference(page);
    		TAILQ_INSERT_TAIL(page_queue, page, entries); // insert at front
    	}
    	else {
    		// remove the page from the working set
    		TAILQ_REMOVE(page_queue, page, entries);
    		return page;
    	}

    }

    return NULL; // no pages in queue (bad)
}
Esempio n. 8
0
Assembler::Register RegisterAllocator::allocate_or_fail(Assembler::Register* next_table, Assembler::Register& next) {

#if ENABLE_CSE
  //try to free the free register without notation firstly.
  Register next_with_notation = Assembler::no_reg;
#endif

  // Use a round-robin strategy to allocate the registers.
  const Register current = next;
  do {
    next = next_table[next];
    // Check to see whether or not the register is available for allocation.
    if (!is_referenced(next) && !is_mapping_something(next)) {
      // Setup a reference to the newly allocated register.

#if ENABLE_CSE
      if (!is_notated(next)) {
        REFERENCE_AND_RETURN(next);
      } else if ( next_with_notation == Assembler::no_reg) {
        next_with_notation = next;
      }
#else
      REFERENCE_AND_RETURN(next);
#endif

    }
  } while(next != current);
  // Couldn't allocate a register without spilling.

#if ENABLE_CSE
  if ( next_with_notation != Assembler::no_reg ) {
    REFERENCE_AND_RETURN(next_with_notation);
  }
#endif

  return Assembler::no_reg;
}
Esempio n. 9
0
File: swapper.c Progetto: gz/aos10
/**
 * Write callback for the NFS write function in case we swap out.
 * Note that because we cannot write 4096 bytes in one chunk
 * we split the writes up in 512 byte chunks. So this function
 * is called multiple times by the NFS library.
 *
 * @param token pointer to the page queue item we are swapping out
 */
static void swap_write_callback(uintptr_t token, int status, fattr_t *attr) {

	page_queue_item* page = (page_queue_item*) token;
	page_table_entry* pte = pager_table_lookup(page->tid, page->virtual_address);
	file_table_entry* swap_fd = get_process(root_thread_g)->filetable[SWAP_FD];

	switch (status) {
		case NFS_OK:
		{
			// update file attributes
			swap_fd->file->status.st_size = attr->size;
			swap_fd->file->status.st_atime = attr->atime.useconds / 1000;

			page->to_swap -= BATCH_SIZE;

			// swapping complete, can we now finally free the frame?
			if(page->to_swap == 0) {
				if(!is_referenced(page)) {

					dprintf(1, "page is swapped out\n");
					if(!page->process_deleted) {
						frame_free(CLEAR_LOWER_BITS(pte->address));
						mark_swapped(pte, page->swap_offset);

						// restart the thread who ran out of memory
						if(!L4_IsNilThread(page->initiator))
							send_ipc_reply(page->initiator, L4_PAGEFAULT, 0);
					}
					else {} // page was killed, nothing to do

					TAILQ_REMOVE(&swapping_pages_head, page, entries);
					free(page);

				}
				else {
					dprintf(1, "page is swapped out but referenced in the mean time\n");
					// page has been referenced inbetween swapping out
					// we need to restart the whole swap procedure
					TAILQ_REMOVE(&swapping_pages_head, page, entries);

					if(!L4_IsNilThread(page->initiator)) {
						send_ipc_reply(page->initiator, L4_PAGEFAULT, 0);
					}

					if(!page->process_deleted) {
						page->initiator = L4_nilthread;
						TAILQ_INSERT_TAIL(&active_pages_head, page, entries);
					}
					else {
						free(page);
					}

				}

			}

		}
		break;

		case NFSERR_NOSPC:
			dprintf(0, "System ran out of memory _and_ swap space (this is bad).\n");
			TAILQ_REMOVE(&swapping_pages_head, page, entries);
			free(page);
			assert(FALSE);
		break;

		default:
			dprintf(0, "%s: Bad NFS status (%d) from callback.\n", __FUNCTION__, status);
			TAILQ_REMOVE(&swapping_pages_head, page, entries);
			free(page);
			assert(FALSE);
			// We could probably try to restart swapping here but since it failed before
			// we don't see much point in this.
		break;
	}

}
Esempio n. 10
0
Assembler::Register RegisterAllocator::allocate_float_register() {
#if ENABLE_ARM_VFP
#if 0
  // This change improve the caching of locals in registers.
  // But the more value that are cached in registers the more
  // values need to be written into memory at method call.
  // Find the best fit
  {
    const Register start = Register(_next_float_allocate & ~1);
    Register next = next_vfp_register(start, (Assembler::number_of_float_registers - 8));
    do {
      const bool f0 = !is_referenced(Register(next+0)) && !is_mapping_something(Register(next+0));
      const bool f1 = !is_referenced(Register(next+1)) && !is_mapping_something(Register(next+1));
      if ((f0 + f1) == 1) {
      Register r = next;
      if ( f0 == false) {
        r = Register(next + 1);
        }

       reference(r);

       return r;
      }
      next = next_vfp_register(next, 2);
    } while (next != start);
  }
#endif

  // Find a free register
  {
    const Register start = _next_float_allocate;
    Register next = start;

    do {
      if( !is_referenced(next) && !is_mapping_something(next)) {

        reference(next);

        _next_float_allocate = next_vfp_register(next, 1);
        return next;
      }
      next = next_vfp_register(next, 1);
    } while (next != start);
  }

  // Nothing free spill registers
  {
    const Register start = _next_float_spill;
    Register next = start;
    do {
      if (is_referenced(next)) {
        continue;
      }
#if ENABLE_INLINE
      if (Compiler::current()->conforming_frame()->not_null() &&
          Compiler::current()->conforming_frame()->is_mapping_something(next)) {
        continue;
      }
#endif // ENABLE_INLINE
      spill(next);

      reference(next);
      _next_float_spill = next_vfp_register(next, 1);
      return next;

    } while ((next = next_vfp_register(next, 1)) != start);
  }
  GUARANTEE(false, "Cannot allocate VFP registers for a float");
  return Assembler::no_reg;
#else  // !ENABLE_ARM_VFP
  return allocate(_next_register_table, _next_float_allocate, _next_float_spill);
#endif // ENABLE_ARM_VFP
}
Esempio n. 11
0
Assembler::Register RegisterAllocator::allocate_double_register() {
  {
    const Register start = Register( next_vfp_register( _next_float_allocate, 1) & ~1);
    Register next = start;

    do {
      if (!is_referenced(Register(next + 0)) &&
        !is_referenced(Register(next + 1)) &&
          !is_mapping_something(Register(next + 0)) &&
        !is_mapping_something(Register(next + 1))) {

      reference(Register(next + 0));
        reference(Register(next + 1));

        _next_float_allocate = next_vfp_register(next, 2);
        return next;
      }
      next = next_vfp_register(next, 2);
    } while (next != start);
  }

#if 0
  // This change improve the caching of locals in registers.
  // But the more value that are cached in registers the more
  // values need to be written into memory at method call.
  // Try and find a half filled register pair
  {
    const Register start = Register((_next_float_spill) & ~1);
    Register next = next_vfp_register(start, 2);
    Register end = next_vfp_register(start, 8);
    do {
      if (is_referenced(Register(next+0)) || is_referenced(Register(next+1))) {
        continue;
      }
      const bool f0 = is_mapping_something(Register(next+0));
      const bool f1 = is_mapping_something(Register(next+1));

      if ((f0 + f1) == 1) {
        spill( f0 ? next : Register( next + 1) );

        reference(Register(next + 0));
        reference(Register(next + 1));
        _next_float_spill = next_vfp_register(next, 2);
      return next;
      }
      next = next_vfp_register(next, 2);
    } while (next != end);
  }
#endif

  // Nothing free spill registers
  {
    const Register start = Register( next_vfp_register( _next_float_spill, 1) & ~1);
    Register next = start;
    do {
      if (is_referenced(Register(next+0)) || is_referenced(Register(next+1))) {
        continue;
      }
#if ENABLE_INLINE
      if (Compiler::current()->conforming_frame()->not_null() &&
          (Compiler::current()->conforming_frame()->is_mapping_something(Register(next+0)) ||
            Compiler::current()->conforming_frame()->is_mapping_something(Register(next+1)))) {
        continue;
      }
#endif
      spill(Register(next+0));
      spill(Register(next+1));

      reference(Register(next+0));
      reference(Register(next+1));
      _next_float_spill = next_vfp_register(next, 2);
      return next;

    } while ((next = next_vfp_register(next, 2)) != start);
  }
  GUARANTEE(false, "Cannot allocate VFP registers for a double");
  return Assembler::no_reg;
}