Exemple #1
0
int		treat_action(t_socket *sock,
			     struct sockaddr_in addr)
{
  int		i;
  int		addrl;
  char		buff[21];

  addrl = sizeof(addr);
  if ((sock->tmp_sock = accept(sock->main_sock,
			       (struct sockaddr *)&addr,
			       (socklen_t *)&addrl)) < 0)
    write(2, "Accept new connection failed\n", 29);
  i = read(sock->tmp_sock, buff, 20);
  buff[i] = '\0';
  if ((i = -1) && check_pseudo(sock, buff) == -1)
    return (-1);
  if (write(1, buff, my_strlen(buff)) < 0 ||
      write(1, " is now connected\n", 18) < 0)
    return (-1);
  while (++i < MAX_CLIENTS)
    if (sock->cli_sock[i] == 0 && !(sock->status[i] = 0))
      {
	sock->cli_sock[i] = sock->tmp_sock;
	send_list_cli(sock, sock->cli_sock[i], sock->pseudo[i]);
	notify_all(sock, sock->pseudo[i], 1);
	break;
      }
  return (0);
}
Exemple #2
0
void Text::cut() 
{
	// ---- check for reasonable selection ----
	unsigned line1 = selection_.line1();
	unsigned line2 = selection_.line2();
	unsigned column1 = selection_.column1();
	unsigned column2 = selection_.column2();
	if ((line1 > line2) || ((line1 == line2) && (column1 >= column2))) 
	{
		return;
	}

	// ---- copy to cut/copy/paste buffer ----
	copy();

	// ---- remove from text buffer ---
	int index0 = text_->LineIndex(line1) + column1;
	int index1 = text_->LineIndex(line2) + column2;
	int len = index1 - index0 + 1;
	text_->Delete(index0, len);

	// ---- update view ----
	insertion_.line_ = selection_.line1();
	insertion_.column_ = selection_.column1();
	selection_.line2(selection_.line1());
	selection_.column2(selection_.column1());
	needWidth_ = true;
	dirty(true);
	notify_all();
	damage();
}
Exemple #3
0
s32 sys_rwlock_runlock(u32 rw_lock_id)
{
	sys_rwlock.Log("sys_rwlock_runlock(rw_lock_id=0x%x)", rw_lock_id);

	LV2_LOCK;

	const auto rwlock = idm::get<lv2_rwlock_t>(rw_lock_id);

	if (!rwlock)
	{
		return CELL_ESRCH;
	}

	if (!rwlock->readers)
	{
		return CELL_EPERM;
	}

	if (!--rwlock->readers)
	{
		rwlock->notify_all(lv2_lock);
	}

	return CELL_OK;
}
/**
 * Add a host to the list and notify clients about this event
 *
 * @param identity the identity of the host
 * @return the HostEntry
 */
static struct HostEntry *
add_host_to_known_hosts (const struct GNUNET_PeerIdentity *identity)
{
  struct HostEntry *entry;
  struct ReadHostFileContext r;
  char *fn;

  entry = GNUNET_CONTAINER_multipeermap_get (hostmap, identity);
  if (NULL == entry)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding new peer `%s'\n", GNUNET_i2s (identity));
    GNUNET_STATISTICS_update (stats, gettext_noop ("# peers known"), 1,
			      GNUNET_NO);
    entry = GNUNET_new (struct HostEntry);
    entry->identity = *identity;
    GNUNET_assert (GNUNET_OK ==
                   GNUNET_CONTAINER_multipeermap_put (hostmap, &entry->identity, entry,
                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    notify_all (entry);
    fn = get_host_filename (identity);
    if (NULL != fn)
    {
      read_host_file (fn, GNUNET_YES, &r);
      if (NULL != r.hello)
      	update_hello (identity, r.hello);
      if (NULL != r.friend_only_hello)
      	update_hello (identity, r.friend_only_hello);
      GNUNET_free_non_null (r.hello);
      GNUNET_free_non_null (r.friend_only_hello);
      GNUNET_free (fn);
    }
  }
 ~distributor()
 {
   lock();
   done = true;
   notify_all();
   unlock();
   threads.join();
 }
void
ept_invalidate_addr(paddr_t gpaddr)
{
	/* See Vol3B 24.3.3 */
	if (TRUNC_PAGE(gpaddr) == kvtophys(dma_test_page)) {
		kprintf("ept_invalidate_addr>gpaddr = "PFMT"\n",
			gpaddr);
	}

#ifdef HYP_PAE
	notify_all((nb_func_t)__ept_invalidate_addr,
		   (nb_arg_t)bits(gpaddr, 31, 0),
		   (nb_arg_t)bits(gpaddr, 63, 32));
#else
	notify_all((nb_func_t)__ept_invalidate_addr,
		   (nb_arg_t)gpaddr, (nb_arg_t)0);
#endif
}
Exemple #7
0
void Text::backspace() 
{
	if ((insertion_.column_ <= 0) && (insertion_.line_ > 0)) 
	{
		--insertion_.line_;
		if (insertion_.line_ >= text_->Height()) 
		{
			insertion_.column_ = 0;
		} 
		else 
		{
			// --- update insertion point ---
			int index = text_->LineIndex(insertion_.line_);
			//insertion_.column_ = text_->LineOffset(index);

			// ---- delete the character ----
			int delIndex = text_->EndOfLine(index);
			insertion_.column_ = delIndex - index;
			text_->Delete(delIndex, 1);
		}
		needWidth_ = true;
		notify_all();
		damage(); // !!! could only damage from insertion to end of window
	} 
	else if (insertion_.column_ > 0) 
	{
		int oldWidth = text_->Width();
		int index = text_->LineIndex(insertion_.line_);

		// ---- delete the text ---
		text_->Delete(index + insertion_.column_ - 1, 1);
		--insertion_.column_;

		if (text_->Width() != oldWidth) 
		{
			needWidth_ = true;
			notify_all();
		}
		repair();
		damage(insertion_);
		repair();
	}
}
Exemple #8
0
void Text::font(const Font* f) 
{
	Resource::ref(f);
	Resource::unref(font_);
	font_ = f;

	needWidth_ = true;
	notify_all();
	damage();
}
Exemple #9
0
void erts_ddll_lock_driver(DE_Handle *dh, char *name)
{
    DE_ProcEntry *p,*q;
    assert_drv_list_rwlocked();
    notify_all(dh, name, 
	       ERL_DE_PROC_AWAIT_LOAD, am_UP, am_permanent);
    notify_all(dh, name, 
	       ERL_DE_PROC_AWAIT_UNLOAD, am_UP, am_permanent);
    notify_all(dh, name, 
	       ERL_DE_PROC_AWAIT_UNLOAD_ONLY, am_UP, am_permanent);
    
    p = dh->procs; 
    while(p != NULL) {
	q = p;
	p = p->next;
	erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) q);
    }
    dh->procs = NULL;
    erts_ddll_reference_driver(dh);
    dh->status = ERL_DE_PERMANENT;
}
/**
 * Function that is called on each HELLO file in a particular directory.
 * Try to parse the file and add the HELLO to our list.
 *
 * @param cls pointer to 'unsigned int' to increment for each file, or NULL
 *            if the file is from a read-only, read-once resource directory
 * @param fullname name of the file to parse
 * @return GNUNET_OK (continue iteration)
 */
static int
hosts_directory_scan_callback (void *cls, const char *fullname)
{
  unsigned int *matched = cls;
  struct GNUNET_PeerIdentity identity;
  const char *filename;
  struct HostEntry *entry;
  struct GNUNET_HELLO_Message *hello;

  if (GNUNET_DISK_file_test (fullname) != GNUNET_YES)
    return GNUNET_OK;           /* ignore non-files */
  if (strlen (fullname) < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded))
  {
    if (NULL != matched)
      remove_garbage (fullname);
    return GNUNET_OK;
  }
  filename =
      &fullname[strlen (fullname) -
                sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1];
  if (filename[-1] != DIR_SEPARATOR)
  {
    if (NULL != matched)
      remove_garbage (fullname);
    return GNUNET_OK;
  }
  if (GNUNET_OK !=
      GNUNET_CRYPTO_hash_from_string (filename, &identity.hashPubKey))
  {
    if (NULL != (hello = read_host_file (filename)))
    {
      entry = GNUNET_malloc (sizeof (struct HostEntry));
      if (GNUNET_OK ==
	  GNUNET_HELLO_get_id (hello,
			       &entry->identity))
      {
	GNUNET_CONTAINER_multihashmap_put (hostmap, &entry->identity.hashPubKey, entry,
					   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
	entry->hello = hello;
	notify_all (entry);
	return GNUNET_OK;
      }
      GNUNET_free (entry);
    }
    if (NULL != matched)
      remove_garbage (fullname);
    return GNUNET_OK;
  }
  if (NULL != matched)
    (*matched)++;
  add_host_to_known_hosts (&identity);
  return GNUNET_OK;
}
Exemple #11
0
void Text::insertChars(const char* txt, unsigned count) 
{
	TextBuffer text(txt, count, count);

	// ---- insert the text info the buffer ----
	text_->Insert(text_->LineIndex(insertion_.line_) + insertion_.column_,
		txt, count);
	dirty(true);

	if (text.Height() > 1) 
	{
		TextRegion area;
		area.line1(insertion_.line_);
		area.column1(0);
		area.line2(insertion_.line_ + text.Height() - 1);
		area.column2(0);
		insertion_.line_ += text.Height() - 1;
		insertion_.column_ = 0;
		damage(); // !!! could only damage from insertion to end of window
		for (unsigned i = 0; i < text.Height(); ++i) 
		{
			width_ = Math::max(width_, width(text.getNth(i)));
		}
		notify_all();
	} 
	else 
	{
		TextLocation old = insertion_;
		insertion_.column_ += count;
		Coord newWidth = width(text_->getNth(insertion_.line_));
		if (newWidth >= width_) 
		{
			width_ = Math::max(width_, newWidth);
			notify_all();
		}
		repair();
		damage(old);
		repair();
	}
}
 base_artificial_table_backend_t(
         name_string_t const &table_name,
         rdb_context_t *rdb_context,
         lifetime_t<name_resolver_t const &> name_resolver,
         std::shared_ptr<semilattice_readwrite_view_t<auth_semilattice_metadata_t>>
             auth_semilattice_view,
         std::shared_ptr<semilattice_read_view_t<cluster_semilattice_metadata_t>>
             cluster_semilattice_view)
     : caching_cfeed_artificial_table_backend_t(
         table_name, rdb_context, name_resolver),
       m_auth_semilattice_view(std::move(auth_semilattice_view)),
       m_auth_subscription([this](){ notify_all(); }, m_auth_semilattice_view),
       m_cluster_semilattice_view(std::move(cluster_semilattice_view)) {
 }
Exemple #13
0
	OpMultiQ::~OpMultiQ()
	{
		/////////////////////////////////
		// dont accept any more ops
		/////////////////////////////////

		for (auto& grp : mOpGroups)
		{
			grp->Disable();
		}

		/////////////////////////////////
		// drain what ops we have
		/////////////////////////////////

		drain();

		/////////////////////////////////
		// Signal to worker threads that we are ready to go down
		// Spam the worker thread semaphore until it does go down
		// Wait until all worker threads have exited
		/////////////////////////////////

		mbOkToExit = true;

		while (int(mThreadsRunning) != 0)
		{
			notify_all();
			usleep(10);
		}

        for( auto thr : mThreads )
            delete thr;

		/////////////////////////////////
		// trash the groups
		/////////////////////////////////

		OpGroup* pgrp = nullptr;

		for (auto& it : mOpGroups)
		{
			delete it;
		}

		/////////////////////////////////

	}
/**
 * Bind a host address (hello) to a hostId.
 *
 * @param peer the peer for which this is a hello
 * @param hello the verified (!) hello message
 */
static void
bind_address (const struct GNUNET_PeerIdentity *peer,
              const struct GNUNET_HELLO_Message *hello)
{
  char *fn;
  struct HostEntry *host;
  struct GNUNET_HELLO_Message *mrg;
  struct GNUNET_TIME_Absolute delta;

  add_host_to_known_hosts (peer);
  host = GNUNET_CONTAINER_multihashmap_get (hostmap, &peer->hashPubKey);
  GNUNET_assert (host != NULL);
  if (host->hello == NULL)
  {
    host->hello = GNUNET_malloc (GNUNET_HELLO_size (hello));
    memcpy (host->hello, hello, GNUNET_HELLO_size (hello));
  }
  else
  {
    mrg = GNUNET_HELLO_merge (host->hello, hello);
    delta = GNUNET_HELLO_equals (mrg, host->hello, GNUNET_TIME_absolute_get ());
    if (delta.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value)
    {
      GNUNET_free (mrg);
      return;
    }
    GNUNET_free (host->hello);
    host->hello = mrg;
  }
  fn = get_host_filename (peer);
  if (GNUNET_OK == GNUNET_DISK_directory_create_for_file (fn))
  {
    if (GNUNET_SYSERR ==
        GNUNET_DISK_fn_write (fn, host->hello, GNUNET_HELLO_size (host->hello),
                              GNUNET_DISK_PERM_USER_READ |
                              GNUNET_DISK_PERM_USER_WRITE |
                              GNUNET_DISK_PERM_GROUP_READ |
                              GNUNET_DISK_PERM_OTHER_READ))
      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn);

  }
  GNUNET_free (fn);
  notify_all (host);
}
Exemple #15
0
void Text::allocate(Canvas* c, const Allocation& a, Extension& extension) 
{
	canvas_ = c;
	if (! allocation_) 
	{
		allocation_ = new Allocation(a);
		curLowerX_ = 0;
		curLowerY_ = 0;
	} 
	else 
	{
		*allocation_ = a;
	}
	curUpperX_ = curLowerX_ + allocation_->allotment(Dimension_X).span();
	curUpperY_ = curLowerY_ + allocation_->allotment(Dimension_Y).span();

	extension.merge(c, a);
	notify_all();
}
Exemple #16
0
void WindowManager::read_configuration()
{
	Fl_String buf;

	Fl_Config wmconf(fl_find_config_file("wmanager.conf", 0));

	wmconf.set_section("TitleBar");

	wmconf.read("Active color", title_active_color, fl_rgb(0,0,128));
	wmconf.read("Normal color", title_normal_color, fl_rgb(192,192,192));

	wmconf.read("Active color text", title_active_color_text, fl_rgb(255,255,255));
	wmconf.read("Normal color text", title_normal_color_text, fl_rgb(0,0,128));

	wmconf.read("Box type", Titlebar::box_type, 0);
	wmconf.read("Height", Titlebar::default_height, 20);
	wmconf.read("Text align", Titlebar::label_align, 0);
	Titlebar::label_align = real_align(Titlebar::label_align);

	wmconf.set_section("Resize");
	wmconf.read("Opaque resize", Frame::do_opaque, false);
	wmconf.read("Animate", Frame::animate, true);
	wmconf.read("Animate Speed", Frame::animate_speed, 15);

	wmconf.set_section("Misc");

	bool theme = false;
	wmconf.read("Use theme", theme, false);
	if(theme)
	{
		wmconf.read("Theme path", buf, 0);
		Theme::instance()->load(buf);
		Theme::instance()->use(true);
	}
	else
	{
		Theme::instance()->unload();
		Theme::instance()->use(false);
	}

	notify_all();
	read_hotkeys_configuration();
}
Exemple #17
0
void Scheduler::notify_task_completion(
	PhysicalTaskIdentifier physical_task_id)
{
	M3BP_SCHEDULER_TRACE << physical_task_id.identifier();
	std::vector<PhysicalTaskIdentifier> successors;
	{
		std::lock_guard<std::mutex> lock(m_physical_graph_mutex);
		auto it = m_vertices.find(physical_task_id);
		assert(it != m_vertices.end());
		successors = std::move(it->second->successors);
		m_vertices.erase(it);
	}
	for(const auto &succ_id : successors){
		decrement_predecessor_count(succ_id);
	}
	const auto remains = --m_unfinished_task_count;
	if(remains == 0){
		notify_all();
	}
}
/**
 * Add a host to the list.
 *
 * @param identity the identity of the host
 */
static void
add_host_to_known_hosts (const struct GNUNET_PeerIdentity *identity)
{
  struct HostEntry *entry;
  char *fn;

  entry = GNUNET_CONTAINER_multihashmap_get (hostmap, &identity->hashPubKey);
  if (entry != NULL)
    return;
  GNUNET_STATISTICS_update (stats, gettext_noop ("# peers known"), 1,
                            GNUNET_NO);
  entry = GNUNET_malloc (sizeof (struct HostEntry));
  entry->identity = *identity;
  GNUNET_CONTAINER_multihashmap_put (hostmap, &identity->hashPubKey, entry,
                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
  fn = get_host_filename (identity);
  entry->hello = read_host_file (fn);
  GNUNET_free (fn);
  notify_all (entry);
}
Exemple #19
0
s32 sys_event_flag_set(u32 id, u64 bitptn)
{
	sys_event_flag.Log("sys_event_flag_set(id=0x%x, bitptn=0x%llx)", id, bitptn);

	LV2_LOCK;

	const auto eflag = idm::get<lv2_event_flag_t>(id);

	if (!eflag)
	{
		return CELL_ESRCH;
	}

	if (bitptn && ~eflag->pattern.fetch_or(bitptn) & bitptn)
	{
		eflag->notify_all(lv2_lock);
	}
	
	return CELL_OK;
}
Exemple #20
0
void		close_sock(t_socket *sock, int i)
{
  notify_all(sock, sock->pseudo[i], 2);
  write(1, sock->pseudo[i], my_strlen(sock->pseudo[i]));
  write(1, " has quit\n", 10);
  close(sock->cli_sock[i]);
  sock->cli_sock[i] = 0;
#ifdef	DEBUG
  printf("indexed:%d\n", i);
#endif
  if (sock->pseudo[i] == NULL)
    write(1, "NULLED\n", 7);
  remove_pseudoc(sock->pseudo, sock->pseudo[i]);
  while (i + 1 < MAX_CLIENTS)
    {
      sock->cli_sock[i] = sock->cli_sock[i + 1];
      ++i;
    }
  write(1, "closeSockEnded\n", 15);
}
Exemple #21
0
void Text::eraseLine() 
{
	if (insertion_.line_ < text_->Height()) 
	{
		int oldWidth = text_->Width();
		int index0 = text_->LineIndex(insertion_.line_);
		int index1 = text_->BeginningOfNextLine(index0);

		// ---- delete the text ----
		text_->Delete(index0, index1 - index0);

		// --- check for width change ----
		if (text_->Width() != oldWidth)
		{
			needWidth_ = true;
			notify_all();
		}
	}
	insertion_.column_ = 0;
	repair();
	damage(insertion_);
	repair();
}
Exemple #22
0
void Text::reset() 
{
	text_->Delete(0, text_->Length());

	insertion_.line_ = 0;
	insertion_.column_ = 0;

	selection_.line1(0);
	selection_.column1(0);
	selection_.line2(0);
	selection_.column2(0);

	if (textBuffer_)
		delete textBuffer_;
	textBuffer_ = 0;

	deannotate();

	needWidth_ = false;
	width_ = 0;

	dirty(false);
	notify_all();
}
Exemple #23
0
s32 sys_rwlock_wunlock(PPUThread& ppu, u32 rw_lock_id)
{
	sys_rwlock.Log("sys_rwlock_wunlock(rw_lock_id=0x%x)", rw_lock_id);

	LV2_LOCK;

	const auto rwlock = idm::get<lv2_rwlock_t>(rw_lock_id);

	if (!rwlock)
	{
		return CELL_ESRCH;
	}

	if (rwlock->writer.get() != &ppu)
	{
		return CELL_EPERM;
	}

	rwlock->writer.reset();

	rwlock->notify_all(lv2_lock);

	return CELL_OK;
}
void ios_proxy::run(size_t threadNum)
{
	assert(threadNum >= 1);
	boost::lock_guard<boost::mutex> lg(_runMutex);
	if (!_opend)
	{
		_opend = true;
		_runCount = 0;
		_runLock = new boost::asio::io_service::work(_ios);
		_handleList.resize(threadNum);
		size_t rc = 0;
		std::shared_ptr<boost::mutex> blockMutex(new boost::mutex);
		std::shared_ptr<boost::condition_variable> blockConVar(new boost::condition_variable);
		boost::unique_lock<boost::mutex> ul(*blockMutex);
		for (size_t i = 0; i < threadNum; i++)
		{
			boost::thread* newThread = new boost::thread([&, i]
			{
				try
				{
					{
						SetThreadPriority(GetCurrentThread(), _priority);
						DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &_handleList[i], 0, FALSE, DUPLICATE_SAME_ACCESS);
						auto lockMutex = blockMutex;
						auto lockConVar = blockConVar;
						boost::unique_lock<boost::mutex> ul(*lockMutex);
						if (threadNum == ++rc)
						{
							lockConVar->notify_all();
						}
						else
						{
							lockConVar->wait(ul);
						}
					}
					_runCount += _ios.run();
				}
				catch (msg_data::pool_memory_exception&)
				{
					MessageBoxA(NULL, "内存不足", NULL, NULL);
					exit(1);
				}
				catch (boost::exception&)
				{
					MessageBoxA(NULL, "未处理的BOOST异常", NULL, NULL);
					exit(2);
				}
				catch (std::exception&)
				{
					MessageBoxA(NULL, "未处理的STD异常", NULL, NULL);
					exit(3);
				}
				catch (std::shared_ptr<std::string> msg)
				{
					MessageBoxA(NULL, msg->c_str(), NULL, NULL);
					exit(4);
				}
				catch (...)
				{
					MessageBoxA(NULL, "未知异常", NULL, NULL);
					exit(-1);
				}
			});
			_threadsID.insert(newThread->get_id());
			_runThreads.add_thread(newThread);
		}
		blockConVar->wait(ul);
	}
}
Exemple #25
0
s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout)
{
	sys_rwlock.Log("sys_rwlock_wlock(rw_lock_id=0x%x, timeout=0x%llx)", rw_lock_id, timeout);

	const u64 start_time = get_system_time();

	LV2_LOCK;

	const auto rwlock = idm::get<lv2_rwlock_t>(rw_lock_id);

	if (!rwlock)
	{
		return CELL_ESRCH;
	}

	if (rwlock->writer.get() == &ppu)
	{
		return CELL_EDEADLK;
	}

	if (!rwlock->readers && !rwlock->writer)
	{
		rwlock->writer = std::static_pointer_cast<CPUThread>(ppu.shared_from_this());

		return CELL_OK;
	}

	// add waiter; protocol is ignored in current implementation
	sleep_queue_entry_t waiter(ppu, rwlock->wsq);

	while (!ppu.unsignal())
	{
		CHECK_EMU_STATUS;

		if (timeout)
		{
			const u64 passed = get_system_time() - start_time;

			if (passed >= timeout)
			{
				// if the last waiter quit the writer sleep queue, readers must acquire the lock
				if (!rwlock->writer && rwlock->wsq.size() == 1)
				{
					if (rwlock->wsq.front().get() != &ppu)
					{
						throw EXCEPTION("Unexpected");
					}

					rwlock->wsq.clear();
					rwlock->notify_all(lv2_lock);
				}

				return CELL_ETIMEDOUT;
			}

			ppu.cv.wait_for(lv2_lock, std::chrono::microseconds(timeout - passed));
		}
		else
		{
			ppu.cv.wait(lv2_lock);
		}
	}

	if (rwlock->readers || rwlock->writer.get() != &ppu)
	{
		throw EXCEPTION("Unexpected");
	}

	return CELL_OK;
}
Exemple #26
0
/* 
 * Called from erl_process.c.
 */
void erts_ddll_proc_dead(Process *p, ErtsProcLocks plocks) 
{
    erts_driver_t *drv;
    erts_proc_unlock(p, plocks);
    lock_drv_list();
    drv = driver_list;
    while (drv != NULL) {
	if (drv->handle != NULL && drv->handle->status != ERL_DE_PERMANENT) {
	    DE_ProcEntry **pe = &(drv->handle->procs);
	    int kill_ports = (drv->handle->flags & ERL_DE_FL_KILL_PORTS);
	    int left = 0;
	    while ((*pe) != NULL) {
		if ((*pe)->proc == p) {
		    DE_ProcEntry *r = *pe;
		    *pe = r->next;
		    if (!(r->flags & ERL_DE_FL_DEREFERENCED) && 
			r->awaiting_status == ERL_DE_PROC_LOADED) {
			erts_ddll_dereference_driver(drv->handle);
		    }
		    erts_free(ERTS_ALC_T_DDLL_PROCESS, (void *) r);
		} else {
		    if ((*pe)->awaiting_status == ERL_DE_PROC_LOADED) {
			++left;
		    }
		    pe = &((*pe)->next);
		}
	    }
	    if (!left) {
		DE_Handle *dh = drv->handle;
		if (dh->status == ERL_DE_RELOAD ||
		    dh->status == ERL_DE_FORCE_RELOAD) {
		    notify_all(dh, drv->name, 
			       ERL_DE_PROC_AWAIT_LOAD, am_DOWN, am_load_cancelled);
		    erts_free(ERTS_ALC_T_DDLL_HANDLE,dh->reload_full_path);
		    erts_free(ERTS_ALC_T_DDLL_HANDLE,dh->reload_driver_name);
		    dh->reload_full_path = dh->reload_driver_name = NULL; 
		    dh->reload_flags = 0;
		} 
		dh->status = ERL_DE_UNLOAD;
	    }
	    if (!left
		&& erts_atomic32_read_nob(&drv->handle->port_count) > 0) {
		if (kill_ports) {
		    DE_Handle *dh = drv->handle;
		    erts_ddll_reference_driver(dh);
		    dh->status = ERL_DE_FORCE_UNLOAD;
		    unlock_drv_list();
		    kill_ports_driver_unloaded(dh);
		    lock_drv_list(); /* Needed for future list operations */
		    drv = drv->next; /* before allowing destruction */
		    erts_ddll_dereference_driver(dh);
		} else {
		    drv = drv->next;
		}
	    } else {
		drv = drv->next;
	    }
	} else {
	    drv = drv->next;
	}
    }
    unlock_drv_list();
    erts_proc_lock(p, plocks);
}
Exemple #27
0
/* 
   You have to have loaded the driver and the pid state 
   is LOADED or AWAIT_LOAD. You will be removed from the list
   regardless of driver state.
   If the driver is loaded by someone else to, return is
   {ok, pending_process}
   If the driver is loaded but locked by a port, return is
   {ok, pending_driver}
   If the driver is loaded and free to unload (you're the last holding it)
   {ok, unloaded}
   If it's not loaded or not loaded by you
   {error, not_loaded} or {error, not_loaded_by_you}

   Internally, if its in state UNLOADING, just return {ok, pending_driver} and
   remove/decrement this pid (which should be an LOADED tagged one).
   If the state is RELOADING, this pid should be in list as LOADED tagged, 
   only AWAIT_LOAD would be possible but not allowed for unloading, remove it 
   and, if the last LOADED tagged, change from RELOAD to UNLOAD and notify
   any AWAIT_LOAD-waiters with {'DOWN', ref(), driver, name(), load_cancelled}
   If the driver made itself permanent, {'UP', ref(), driver, name(), permanent}
*/
Eterm erl_ddll_try_unload_2(BIF_ALIST_2)
{
    Eterm name_term = BIF_ARG_1;
    Eterm options = BIF_ARG_2;
    char *name = NULL;
    Eterm ok_term = NIL;
    Eterm soft_error_term = NIL;
    erts_driver_t *drv;
    DE_Handle *dh;
    DE_ProcEntry *pe;
    Eterm *hp;
    Eterm t;
    int monitor = 0;
    Eterm l;
    int kill_ports = 0;

    erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);

    for(l = options; is_list(l); l =  CDR(list_val(l))) {
	Eterm opt = CAR(list_val(l));
	Eterm *tp;
	if (is_not_tuple(opt)) {
	    if (opt == am_kill_ports) {
		kill_ports = 1;
		continue;
	    } else {
		goto error;
	    }
	}
	tp = tuple_val(opt);
	if (*tp != make_arityval(2) || tp[1] != am_monitor) {
	    goto error;
	}
	if (tp[2] == am_pending_driver) { 
	    monitor = 1;
	} else if (tp[2] == am_pending) {
	    monitor = 2;
	} else {
	    goto error;
	}
    }
    if (is_not_nil(l)) {
	goto error;
    }

    if ((name = pick_list_or_atom(name_term)) == NULL) {
	goto error;
    }

    lock_drv_list();

    if ((drv = lookup_driver(name)) == NULL) {
	soft_error_term = am_not_loaded;
	goto soft_error;
    }

    if (drv->handle == NULL) {
	soft_error_term = am_linked_in_driver;
	goto soft_error;
    } else if (drv->handle->status == ERL_DE_PERMANENT) {
	soft_error_term = am_permanent;
	goto soft_error;
    }	
    dh = drv->handle;
    if (dh->flags & ERL_DE_FL_KILL_PORTS) {
	kill_ports = 1;
    }
    if ((pe = find_proc_entry(dh, BIF_P, ERL_DE_PROC_LOADED)) == NULL) {
	if (num_procs(dh, ERL_DE_PROC_LOADED) > 0) {
	    soft_error_term = am_not_loaded_by_this_process;
	    goto soft_error;
	}
    } else {
	remove_proc_entry(dh, pe);
	if (!(pe->flags & ERL_DE_FL_DEREFERENCED)) {
	    erts_ddll_dereference_driver(dh);
	}
	erts_free(ERTS_ALC_T_DDLL_PROCESS, pe);
    }
    if (num_procs(dh, ERL_DE_PROC_LOADED) > 0) {
	ok_term = am_pending_process;
	--monitor;
	goto done;
    }
    if (dh->status == ERL_DE_RELOAD ||
	dh->status == ERL_DE_FORCE_RELOAD) {
	notify_all(dh, drv->name, 
		   ERL_DE_PROC_AWAIT_LOAD, am_DOWN, am_load_cancelled);
	erts_free(ERTS_ALC_T_DDLL_HANDLE,dh->reload_full_path);
	erts_free(ERTS_ALC_T_DDLL_HANDLE,dh->reload_driver_name);
	dh->reload_full_path = dh->reload_driver_name = NULL; 
	dh->reload_flags = 0;
    } 
    if (erts_atomic32_read_nob(&dh->port_count) > 0) {
	++kill_ports;
    }
    dh->status = ERL_DE_UNLOAD;
    ok_term = am_pending_driver;
done:
    assert_drv_list_rwlocked();
    if (kill_ports > 1) {
	/* Avoid closing the driver by referencing it */
	erts_ddll_reference_driver(dh);
	dh->status = ERL_DE_FORCE_UNLOAD;
	unlock_drv_list();
	kill_ports_driver_unloaded(dh);
	lock_drv_list(); 
	erts_ddll_dereference_driver(dh);
    } 

    erts_ddll_reference_driver(dh);
    unlock_drv_list();
    erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
    lock_drv_list();
    erts_ddll_dereference_driver(dh);
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
    BIF_P->flags |= F_USING_DDLL;
    if (monitor > 0) {
	Eterm mref = add_monitor(BIF_P, dh, ERL_DE_PROC_AWAIT_UNLOAD);
	hp = HAlloc(BIF_P, 4);
	t = TUPLE3(hp, am_ok, ok_term, mref);
    } else {
	hp = HAlloc(BIF_P, 3);
	t = TUPLE2(hp, am_ok, ok_term);
    }
    if (kill_ports > 1) {
	ERTS_BIF_CHK_EXITED(BIF_P); /* May be exited by port killing */
    }
    unlock_drv_list();
    BIF_RET(t);
 
soft_error:
    unlock_drv_list();
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
    erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
    hp = HAlloc(BIF_P, 3);
    t = TUPLE2(hp, am_error, soft_error_term);
    BIF_RET(t);
 
 error: /* No lock fiddling before going here */
    assert_drv_list_not_locked();
    if (name != NULL) {
	erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
    }
    erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
    BIF_ERROR(BIF_P, BADARG);
}
Exemple #28
0
/*
 * Try to load. If the driver is OK, add as LOADED.  If the driver is
 * UNLOAD, possibly change to reload and add as LOADED, 
 * there should be no other
 * LOADED tagged pid's.  If the driver is RELOAD then add/increment as
 * LOADED (should be some LOADED pid).  If the driver is not present,
 * really load and add as LOADED {ok,loaded} {ok,pending_driver}
 * {error, permanent} {error,load_error()}
 */
BIF_RETTYPE erl_ddll_try_load_3(BIF_ALIST_3)
{
    Eterm path_term = BIF_ARG_1;
    Eterm name_term = BIF_ARG_2;
    Eterm options = BIF_ARG_3;
    char *path = NULL;
    Sint path_len;
    char *name = NULL;
    DE_Handle *dh;
    erts_driver_t *drv;
    int res;
    Eterm soft_error_term = NIL;
    Eterm ok_term = NIL;
    Eterm *hp;
    Eterm t;
    int monitor = 0;
    int reload = 0;
    Eterm l;
    Uint flags = 0;
    int kill_ports = 0;
    int do_build_load_error = 0;
    int build_this_load_error = 0;
    int encoding;

    for(l = options; is_list(l); l =  CDR(list_val(l))) {
	Eterm opt = CAR(list_val(l));
	Eterm *tp;
	if (is_not_tuple(opt)) {
	    goto error;
	}
	tp = tuple_val(opt);
	if (*tp != make_arityval(2) || is_not_atom(tp[1])) {
	    goto error;
	}
	switch (tp[1]) {
	case am_driver_options:
	    {
		Eterm ll;
		for(ll = tp[2]; is_list(ll); ll = CDR(list_val(ll))) {
		    Eterm dopt = CAR(list_val(ll));
		    if (dopt == am_kill_ports) {
			flags |= ERL_DE_FL_KILL_PORTS;
		    } else {
			goto error;
		    }
		}
		if (is_not_nil(ll)) {
		    goto error;
		}
	    }
	    break;
	case am_monitor:
	    if (tp[2] == am_pending_driver) {
		monitor = 1;
	    } else if (tp[2] == am_pending ) {
		monitor = 2;
	    } else {
		goto error;
	    }
	    break;
	case am_reload:
	    if (tp[2] == am_pending_driver) {
		reload = 1;
	    } else if (tp[2] == am_pending ) {
		reload = 2;
	    } else {
		goto error;
	    }
	    break;
	default:
	    goto error;
	}
    }
    if (is_not_nil(l)) {
	goto error;
    }


    if ((name = pick_list_or_atom(name_term)) == NULL) {
	goto error;
    }

    encoding = erts_get_native_filename_encoding();
    if (encoding == ERL_FILENAME_WIN_WCHAR) {
        /* Do not convert the lib name to utf-16le yet, do that in win32 specific code */
        /* since lib_name is used in error messages */
        encoding = ERL_FILENAME_UTF8;
    }
    path = erts_convert_filename_to_encoding(path_term, NULL, 0,
					     ERTS_ALC_T_DDLL_TMP_BUF, 1, 0,
					     encoding, &path_len,
					     sys_strlen(name) + 2); /* might need path separator */
    if (!path) {
	goto error;
    }
    ASSERT(path_len > 0 && path[path_len-1] == 0);
    while (--path_len > 0 && (path[path_len-1] == '\\' || path[path_len-1] == '/'))
	;
    path[path_len++] = '/';
    sys_strcpy(path+path_len,name);

    erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
    lock_drv_list();
    if ((drv = lookup_driver(name)) != NULL) {
	if (drv->handle == NULL) {
	    /* static_driver */
	    soft_error_term = am_linked_in_driver;
	    goto soft_error;
	} else {
	    dh = drv->handle;
	    if (dh->status == ERL_DE_OK) {
		int is_last = is_last_user(dh, BIF_P);
		if (reload == 1 && !is_last) {
		    /*Want reload if no other users, 
		      but there are others...*/
		    soft_error_term = am_pending_process;
		    goto soft_error;
		} 
		if (reload != 0) {
		    DE_ProcEntry *old;
		    if ((dh->flags & ERL_FL_CONSISTENT_MASK) != 
			(flags &  ERL_FL_CONSISTENT_MASK)) {
			soft_error_term = am_inconsistent;
			goto soft_error;
		    }
		    if ((old = find_proc_entry(dh, BIF_P,
					       ERL_DE_PROC_LOADED)) ==
			NULL) {
			soft_error_term = am_not_loaded_by_this_process;
			goto soft_error;
		    } else {
			remove_proc_entry(dh, old);
			erts_ddll_dereference_driver(dh);
			erts_free(ERTS_ALC_T_DDLL_PROCESS, old);
		    }
		    /* Reload requested and granted */
		    dereference_all_processes(dh);
		    set_driver_reloading(dh, BIF_P, path, name, flags);
		    if (dh->flags & ERL_DE_FL_KILL_PORTS) {
			kill_ports = 1;
		    }
		    ok_term = (reload == 1) ? am_pending_driver : 
			am_pending_process;
		} else {
		    /* Already loaded and healthy (might be by me) */
		    if (sys_strcmp(dh->full_path, path) || 
			(dh->flags & ERL_FL_CONSISTENT_MASK) != 
			(flags &  ERL_FL_CONSISTENT_MASK)) {
			soft_error_term = am_inconsistent;
			goto soft_error;
		    }
		    add_proc_loaded(dh, BIF_P);
		    erts_ddll_reference_driver(dh);
		    monitor = 0;
		    ok_term = mkatom("already_loaded");
		}
	    } else if (dh->status == ERL_DE_UNLOAD ||
		       dh->status == ERL_DE_FORCE_UNLOAD) {
		/* pending driver */
		if (reload != 0) {
		    soft_error_term = am_not_loaded_by_this_process;
		    goto soft_error;
		} 
		if (sys_strcmp(dh->full_path, path) || 
		    (dh->flags & ERL_FL_CONSISTENT_MASK) != 
		    (flags &  ERL_FL_CONSISTENT_MASK)) {
		    soft_error_term = am_inconsistent;
		    goto soft_error;
		}
		dh->status = ERL_DE_OK;
		notify_all(dh, drv->name, 
			   ERL_DE_PROC_AWAIT_UNLOAD, am_UP, 
			   am_unload_cancelled);
		add_proc_loaded(dh, BIF_P);
		erts_ddll_reference_driver(dh);
		monitor = 0;
		ok_term = mkatom("already_loaded");
	    } else if (dh->status == ERL_DE_RELOAD ||
		       dh->status == ERL_DE_FORCE_RELOAD) {
		if (reload != 0) {
		    soft_error_term = am_pending_reload;
		    goto soft_error;
		}
		if (sys_strcmp(dh->reload_full_path, path) || 
		    (dh->reload_flags & ERL_FL_CONSISTENT_MASK) != 
		        (flags &  ERL_FL_CONSISTENT_MASK)) {
		    soft_error_term = am_inconsistent;
		    goto soft_error;
		}
		/* Load of granted unload... */
		/* Don't reference, will happen after reload */
		add_proc_loaded_deref(dh, BIF_P);
		++monitor;
		ok_term = am_pending_driver;
	    } else { /* ERL_DE_PERMANENT */
		soft_error_term = am_permanent;
		goto soft_error;
	    }
	}
    } else { /* driver non-existing */
	if (reload != 0) {
	    soft_error_term = am_not_loaded;
	    goto soft_error;
	} 
	if ((res = load_driver_entry(&dh, path, name)) !=  ERL_DE_NO_ERROR) {
	    build_this_load_error = res;
	    do_build_load_error = 1;
	    soft_error_term = am_undefined;
	    goto soft_error;
	} else {
	    dh->flags = flags;
	    add_proc_loaded(dh, BIF_P);
	    first_ddll_reference(dh);
	    monitor = 0;
	    ok_term = mkatom("loaded");
	}
    }
    assert_drv_list_rwlocked();
    if (kill_ports) {
 	/* Avoid closing the driver by referencing it */
	erts_ddll_reference_driver(dh);
	ASSERT(dh->status == ERL_DE_RELOAD);
	dh->status = ERL_DE_FORCE_RELOAD;
	unlock_drv_list();
	kill_ports_driver_unloaded(dh);
	/* Dereference, eventually causing driver destruction */
	lock_drv_list(); 
	erts_ddll_dereference_driver(dh);
    } 

    erts_ddll_reference_driver(dh);
    unlock_drv_list();
    erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
    lock_drv_list();
    erts_ddll_dereference_driver(dh);

    BIF_P->flags |= F_USING_DDLL;
    if (monitor) {
	Eterm mref = add_monitor(BIF_P, dh, ERL_DE_PROC_AWAIT_LOAD);
	hp = HAlloc(BIF_P, 4);
	t = TUPLE3(hp, am_ok, ok_term, mref);
    } else {
	hp = HAlloc(BIF_P, 3);
	t = TUPLE2(hp, am_ok, ok_term);
    }
    unlock_drv_list();
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) path);
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
    ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(BIF_P));
    BIF_RET(t);
 soft_error:
    unlock_drv_list();
    erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
    if (do_build_load_error) {
	soft_error_term = build_load_error(BIF_P, build_this_load_error);
    }

    hp = HAlloc(BIF_P, 3);
    t = TUPLE2(hp, am_error, soft_error_term);
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) path);
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
    ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(BIF_P));
    BIF_RET(t);
 error:
    assert_drv_list_not_locked();
    ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(BIF_P));
    if (path != NULL) {
	erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) path);
    }
    if (name != NULL) {
	erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
    }
    BIF_ERROR(BIF_P, BADARG);
}
Exemple #29
0
  void notifyAll() {
	  notify_all();
  }
Exemple #30
0
void SPUThread::set_ch_value(u32 ch, u32 value)
{
	if (Ini.HLELogging.GetValue())
	{
		LOG_NOTICE(SPU, "set_ch_value(ch=%d [%s], value=0x%x)", ch, ch < 128 ? spu_ch_name[ch] : "???", value);
	}

	switch (ch)
	{
	//case SPU_WrSRR0:
	//	SRR0 = value & 0x3FFFC;  //LSLR & ~3
	//	break;
	case SPU_WrOutIntrMbox:
	{
		if (m_type == CPU_THREAD_RAW_SPU)
		{
			std::unique_lock<std::mutex> lock(mutex, std::defer_lock);

			while (!ch_out_intr_mbox.try_push(value))
			{
				CHECK_EMU_STATUS;

				if (is_stopped()) throw CPUThreadStop{};

				if (!lock)
				{
					lock.lock();
					continue;
				}

				cv.wait(lock);
			}

			int_ctrl[2].set(SPU_INT2_STAT_MAILBOX_INT);
			return;
		}
		else
		{
			const u8 code = value >> 24;
			if (code < 64)
			{
				/* ===== sys_spu_thread_send_event (used by spu_printf) ===== */

				LV2_LOCK;

				const u8 spup = code & 63;

				if (!ch_out_mbox.get_count())
				{
					throw EXCEPTION("sys_spu_thread_send_event(value=0x%x, spup=%d): Out_MBox is empty", value, spup);
				}

				if (u32 count = ch_in_mbox.get_count())
				{
					throw EXCEPTION("sys_spu_thread_send_event(value=0x%x, spup=%d): In_MBox is not empty (count=%d)", value, spup, count);
				}

				const u32 data = ch_out_mbox.get_value();

				ch_out_mbox.set_value(data, 0);

				if (Ini.HLELogging.GetValue())
				{
					LOG_NOTICE(SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, value & 0x00ffffff, data);
				}

				const auto queue = this->spup[spup].lock();

				if (!queue)
				{
					LOG_WARNING(SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (value & 0x00ffffff), data);
					return ch_in_mbox.set_values(1, CELL_ENOTCONN); // TODO: check error passing
				}

				if (queue->events.size() >= queue->size)
				{
					return ch_in_mbox.set_values(1, CELL_EBUSY);
				}

				queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, m_id, ((u64)spup << 32) | (value & 0x00ffffff), data);

				return ch_in_mbox.set_values(1, CELL_OK);
			}
			else if (code < 128)
			{
				/* ===== sys_spu_thread_throw_event ===== */

				LV2_LOCK;

				const u8 spup = code & 63;

				if (!ch_out_mbox.get_count())
				{
					throw EXCEPTION("sys_spu_thread_throw_event(value=0x%x, spup=%d): Out_MBox is empty", value, spup);
				}

				const u32 data = ch_out_mbox.get_value();

				ch_out_mbox.set_value(data, 0);

				if (Ini.HLELogging.GetValue())
				{
					LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, value & 0x00ffffff, data);
				}

				const auto queue = this->spup[spup].lock();

				if (!queue)
				{
					LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (value & 0x00ffffff), data);
					return;
				}

				// TODO: check passing spup value
				if (queue->events.size() >= queue->size)
				{
					LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (value & 0x00ffffff), data);
					return;
				}

				queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, m_id, ((u64)spup << 32) | (value & 0x00ffffff), data);
				return;
			}
			else if (code == 128)
			{
				/* ===== sys_event_flag_set_bit ===== */

				LV2_LOCK;

				const u32 flag = value & 0xffffff;

				if (!ch_out_mbox.get_count())
				{
					throw EXCEPTION("sys_event_flag_set_bit(value=0x%x (flag=%d)): Out_MBox is empty", value, flag);
				}

				if (u32 count = ch_in_mbox.get_count())
				{
					throw EXCEPTION("sys_event_flag_set_bit(value=0x%x (flag=%d)): In_MBox is not empty (%d)", value, flag, count);
				}

				const u32 data = ch_out_mbox.get_value();

				ch_out_mbox.set_value(data, 0);

				if (flag > 63)
				{
					throw EXCEPTION("sys_event_flag_set_bit(id=%d, value=0x%x (flag=%d)): Invalid flag", data, value, flag);
				}

				if (Ini.HLELogging.GetValue())
				{
					LOG_WARNING(SPU, "sys_event_flag_set_bit(id=%d, value=0x%x (flag=%d))", data, value, flag);
				}

				const auto eflag = idm::get<lv2_event_flag_t>(data);

				if (!eflag)
				{
					return ch_in_mbox.set_values(1, CELL_ESRCH);
				}

				const u64 bitptn = 1ull << flag;

				if (~eflag->pattern.fetch_or(bitptn) & bitptn)
				{
					// notify if the bit was set
					eflag->notify_all(lv2_lock);
				}
				
				return ch_in_mbox.set_values(1, CELL_OK);
			}
			else if (code == 192)
			{
				/* ===== sys_event_flag_set_bit_impatient ===== */

				LV2_LOCK;

				const u32 flag = value & 0xffffff;

				if (!ch_out_mbox.get_count())
				{
					throw EXCEPTION("sys_event_flag_set_bit_impatient(value=0x%x (flag=%d)): Out_MBox is empty", value, flag);
				}

				const u32 data = ch_out_mbox.get_value();

				ch_out_mbox.set_value(data, 0);

				if (flag > 63)
				{
					throw EXCEPTION("sys_event_flag_set_bit_impatient(id=%d, value=0x%x (flag=%d)): Invalid flag", data, value, flag);
				}

				if (Ini.HLELogging.GetValue())
				{
					LOG_WARNING(SPU, "sys_event_flag_set_bit_impatient(id=%d, value=0x%x (flag=%d))", data, value, flag);
				}

				const auto eflag = idm::get<lv2_event_flag_t>(data);

				if (!eflag)
				{
					return;
				}

				const u64 bitptn = 1ull << flag;

				if (~eflag->pattern.fetch_or(bitptn) & bitptn)
				{
					// notify if the bit was set
					eflag->notify_all(lv2_lock);
				}
				
				return;
			}
			else
			{
				if (ch_out_mbox.get_count())
				{
					throw EXCEPTION("SPU_WrOutIntrMbox: unknown data (value=0x%x); Out_MBox = 0x%x", value, ch_out_mbox.get_value());
				}
				else
				{
					throw EXCEPTION("SPU_WrOutIntrMbox: unknown data (value=0x%x)", value);
				}
			}
		}
	}

	case SPU_WrOutMbox:
	{
		std::unique_lock<std::mutex> lock(mutex, std::defer_lock);

		while (!ch_out_mbox.try_push(value))
		{
			CHECK_EMU_STATUS;

			if (is_stopped()) throw CPUThreadStop{};

			if (!lock)
			{
				lock.lock();
				continue;
			}

			cv.wait(lock);
		}

		return;
	}

	case MFC_WrTagMask:
	{
		ch_tag_mask = value;
		return;
	}

	case MFC_WrTagUpdate:
	{
		ch_tag_stat.set_value(ch_tag_mask); // hack
		return;
	}

	case MFC_LSA:
	{
		if (value >= 0x40000)
		{
			break;
		}

		ch_mfc_args.lsa = value;
		return;
	}

	case MFC_EAH:
	{
		ch_mfc_args.eah = value;
		return;
	}

	case MFC_EAL:
	{
		ch_mfc_args.eal = value;
		return;
	}

	case MFC_Size:
	{
		if (value > 16 * 1024)
		{
			break;
		}

		ch_mfc_args.size = (u16)value;
		return;
	}

	case MFC_TagID:
	{
		if (value >= 32)
		{
			break;
		}

		ch_mfc_args.tag = (u16)value;
		return;
	}

	case MFC_Cmd:
	{
		process_mfc_cmd(value);
		ch_mfc_args = {}; // clear non-persistent data
		return;
	}

	case MFC_WrListStallAck:
	{
		if (value >= 32)
		{
			break;
		}

		size_t processed = 0;

		for (size_t i = 0; i < mfc_queue.size(); i++)
		{
			if (mfc_queue[i].second.tag == value)
			{
				do_dma_list_cmd(mfc_queue[i].first, mfc_queue[i].second);
				mfc_queue[i].second.tag = 0xdead;
				processed++;
			}
		}

		while (processed)
		{
			for (size_t i = 0; i < mfc_queue.size(); i++)
			{
				if (mfc_queue[i].second.tag == 0xdead)
				{
					mfc_queue.erase(mfc_queue.begin() + i);
					processed--;
					break;
				}
			}
		}

		return;
	}

	case SPU_WrDec:
	{
		ch_dec_start_timestamp = get_timebased_time();
		ch_dec_value = value;
		return;
	}

	case SPU_WrEventMask:
	{
		// detect masking events with enabled interrupt status
		if (value && ch_event_stat.load() & SPU_EVENT_INTR_ENABLED)
		{
			throw EXCEPTION("SPU Interrupts not implemented (mask=0x%x)", value);
		}

		// detect masking unimplemented events
		if (value & ~SPU_EVENT_IMPLEMENTED)
		{
			break;
		}

		ch_event_mask.store(value);
		return;
	}

	case SPU_WrEventAck:
	{
		if (value & ~SPU_EVENT_IMPLEMENTED)
		{
			break;
		}

		ch_event_stat &= ~value;
		return;
	}
	}

	throw EXCEPTION("Unknown/illegal channel (ch=%d [%s], value=0x%x)", ch, ch < 128 ? spu_ch_name[ch] : "???", value);
}