Example #1
0
File: bus.c Project: uselessd/bus
/**
 * Wait for a message to be broadcasted on the bus.
 * The caller should make a copy of the received message,
 * without freeing the original copy, and parse it in a
 * separate thread. When the new thread has started be
 * started, the caller of this function should then
 * either call `bus_poll` again or `bus_poll_stop`.
 * 
 * @param   bus    Bus information
 * @param   flags  `BUS_NOWAIT` if the bus should fail and set `errno` to
 *                 `EAGAIN` if there isn't already a message available on the bus
 * @return         The received message, `NULL` on error
 */
const char *
bus_poll(bus_t *bus, int flags)
{
	int state = 0, saved_errno;
	if (!bus->first_poll) {
		t(release_semaphore(bus, W, SEM_UNDO));  state++;
		t(acquire_semaphore(bus, S, SEM_UNDO));  state++;
		t(zero_semaphore(bus, S, 0));
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS_ME_HARDER
		t(zero_semaphore(bus, N, 0));
#endif
		t(release_semaphore(bus, S, SEM_UNDO));  state--;
		t(acquire_semaphore(bus, W, SEM_UNDO));  state--;
		t(release_semaphore(bus, Q, 0));
	} else {
		bus->first_poll = 0;
	}
	state--;
	t(zero_semaphore(bus, Q, F(BUS_NOWAIT, IPC_NOWAIT)));
	return bus->message;

fail:
	saved_errno = errno;
	if (state > 1)
		release_semaphore(bus, S, SEM_UNDO);
	if (state > 0)
		acquire_semaphore(bus, W, SEM_UNDO);
	if (state < 0)
		bus->first_poll = 1;
	errno = saved_errno;
	return NULL;
}
Example #2
0
File: bus.c Project: uselessd/bus
/**
 * Broadcast a message on a bus
 * 
 * @param   bus      Bus information
 * @param   message  The message to write, may not be longer than
 *                   `BUS_MEMORY_SIZE` including the NUL-termination
 * @param   flags    `BUS_NOWAIT` if this function shall fail if
 *                   another process is currently running this
 *                   procedure
 * @return           0 on success, -1 on error
 */
int
bus_write(const bus_t *bus, const char *message, int flags)
{
	int saved_errno;
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS
	int state = 0;
#endif
	if (acquire_semaphore(bus, X, SEM_UNDO | F(BUS_NOWAIT, IPC_NOWAIT)) == -1)
		return -1;
	t(zero_semaphore(bus, W, 0));
	write_shared_memory(bus, message);
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS
	t(release_semaphore(bus, N, SEM_UNDO));  state++;
#endif
	t(write_semaphore(bus, Q, 0));
	t(zero_semaphore(bus, S, 0));
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS
	t(acquire_semaphore(bus, N, SEM_UNDO));  state--;
#endif
	t(release_semaphore(bus, X, SEM_UNDO));
	return 0;

fail:
	saved_errno = errno;
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS
	if (state > 0)
		acquire_semaphore(bus, N, SEM_UNDO);
#endif
	release_semaphore(bus, X, SEM_UNDO);
	errno = saved_errno;
	return -1;
}
Example #3
0
File: bus.c Project: uselessd/bus
/**
 * Announce that the thread is listening on the bus.
 * This is required so the will does not miss any
 * messages due to race conditions. Additionally,
 * not calling this function will cause the bus the
 * misbehave, is `bus_poll` is written to expect
 * this function to have been called.
 * 
 * @param   bus  Bus information
 * @return       0 on success, -1 on error
 */
int
bus_poll_start(bus_t *bus)
{
	bus->first_poll = 1;
	t(release_semaphore(bus, S, SEM_UNDO));
	t(release_semaphore(bus, Q, 0));
	return 0;

fail:
	return -1;
}
/* Please see header for specification */
Anvil::Semaphore::~Semaphore()
{
    Anvil::ObjectTracker::get()->unregister_object(Anvil::ObjectType::SEMAPHORE,
                                                    this);

    release_semaphore();
}
Example #5
0
File: bus.c Project: uselessd/bus
/**
 * Listen (in a loop, forever) for new message on a bus
 * 
 * @param   bus        Bus information
 * @param   callback   Function to call when a message is received, the
 *                     input parameters will be the read message and
 *                     `user_data` from `bus_read`'s parameter with the
 *                     same name. The message must have been parsed or
 *                     copied when `callback` returns as it may be over
 *                     overridden after that time. `callback` should
 *                     return either of the the values:
 *                       *  0:  stop listening
 *                       *  1:  continue listening
 *                       * -1:  an error has occurred
 *                     However, the function [`bus_read`] will invoke
 *                     `callback` with `message` set to `NULL`one time
 *                     directly after it has started listening on the
 *                     bus. This is to the the program now it can safely
 *                     continue with any action that requires that the
 *                     programs is listening on the bus.
 * @param   user_data  Parameter passed to `callback`
 * @param   timeout    The time the operation shall fail with errno set
 *                     to `EAGAIN` if not completed, note that the callback
 *                     function may or may not have been called
 * @param   clockid    The ID of the clock the `timeout` is measured with,
 *                     it most be a predictable clock
 * @return             0 on success, -1 on error
 */
int bus_read_timed(const bus_t *bus, int (*callback)(const char *message, void *user_data),
		   void *user_data, const struct timespec *timeout, clockid_t clockid)
{
	int r, state = 0, saved_errno;
	struct timespec delta;
	if (!timeout)
		return bus_read(bus, callback, user_data);

	DELTA;
	if (release_semaphore_timed(bus, S, SEM_UNDO, &delta) == -1)
		return -1;
	t(r = callback(NULL, user_data));
	if (!r)  goto done;
	for (;;) {
		DELTA;
		t(release_semaphore_timed(bus, Q, 0, &delta));
		DELTA;
		t(zero_semaphore_timed(bus, Q, 0, &delta));
		t(r = callback(bus->message, user_data));
		if (!r)  goto done;
		t(release_semaphore(bus, W, SEM_UNDO));  state++;
		t(acquire_semaphore(bus, S, SEM_UNDO));  state++;
		t(zero_semaphore(bus, S, 0));
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS_ME_HARDER
		t(zero_semaphore(bus, N, 0));
#endif
		t(release_semaphore(bus, S, SEM_UNDO));  state--;
		t(acquire_semaphore(bus, W, SEM_UNDO));  state--;
	}

fail:
	saved_errno = errno;
	if (state > 1)
		release_semaphore(bus, S, SEM_UNDO);
	if (state > 0)
		acquire_semaphore(bus, W, SEM_UNDO);
	acquire_semaphore(bus, S, SEM_UNDO);
	errno = saved_errno;
	return -1;

done:
	t(acquire_semaphore(bus, S, SEM_UNDO));
	return 0;
}
Example #6
0
void produce(int *memory, int semaphore_id)
{
    while(1) {
        acquire_semaphore(semaphore_id);
        if(memory[SIZE_INDEX] < ARRAY_SIZE) {
            create_task(memory);
        }
        release_semaphore(semaphore_id);
        sleep(1);
    }
}
Example #7
0
static int semaphore_signal( struct object *obj, unsigned int access )
{
    struct semaphore *sem = (struct semaphore *)obj;
    assert( obj->ops == &semaphore_ops );

    if (!(access & SEMAPHORE_MODIFY_STATE))
    {
        set_error( STATUS_ACCESS_DENIED );
        return 0;
    }
    return release_semaphore( sem, 1, NULL );
}
Example #8
0
File: bus.c Project: uselessd/bus
/**
 * Broadcast a message on a bus
 * 
 * @param   bus      Bus information
 * @param   message  The message to write, may not be longer than
 *                   `BUS_MEMORY_SIZE` including the NUL-termination
 * @param   timeout  The time the operation shall fail with errno set
 *                   to `EAGAIN` if not completed
 * @param   clockid  The ID of the clock the `timeout` is measured with,
 *                   it most be a predictable clock
 * @return           0 on success, -1 on error
 */
int bus_write_timed(const bus_t *bus, const char *message,
		    const struct timespec *timeout, clockid_t clockid)
{
	int saved_errno;
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS
	int state = 0;
#endif
	struct timespec delta;
	if (!timeout)
		return bus_write(bus, message, 0);

	DELTA;
	if (acquire_semaphore_timed(bus, X, SEM_UNDO, &delta) == -1)
		return -1;
	DELTA;
	t(zero_semaphore_timed(bus, W, 0, &delta));
	write_shared_memory(bus, message);
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS
	t(release_semaphore(bus, N, SEM_UNDO));  state++;
#endif
	t(write_semaphore(bus, Q, 0));
	t(zero_semaphore(bus, S, 0));
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS
	t(acquire_semaphore(bus, N, SEM_UNDO));  state--;
#endif
	t(release_semaphore(bus, X, SEM_UNDO));
	return 0;

fail:
	saved_errno = errno;
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS
	if (state > 0)
		acquire_semaphore(bus, N, SEM_UNDO);
#endif
	release_semaphore(bus, X, SEM_UNDO);
	errno = saved_errno;
	return -1;

}
Example #9
0
File: bus.c Project: uselessd/bus
/**
 * Listen (in a loop, forever) for new message on a bus
 * 
 * @param   bus        Bus information
 * @param   callback   Function to call when a message is received, the
 *                     input parameters will be the read message and
 *                     `user_data` from `bus_read`'s parameter with the
 *                     same name. The message must have been parsed or
 *                     copied when `callback` returns as it may be over
 *                     overridden after that time. `callback` should
 *                     return either of the the values:
 *                       *  0:  stop listening
 *                       *  1:  continue listening
 *                       * -1:  an error has occurred
 *                     However, the function [`bus_read`] will invoke
 *                     `callback` with `message` set to `NULL`one time
 *                     directly after it has started listening on the
 *                     bus. This is to the the program now it can safely
 *                     continue with any action that requires that the
 *                     programs is listening on the bus.
 * @param   user_data  Parameter passed to `callback`
 * @return             0 on success, -1 on error
 */
int
bus_read(const bus_t *bus, int (*callback)(const char *message, void *user_data), void *user_data)
{
	int r, state = 0, saved_errno;
	if (release_semaphore(bus, S, SEM_UNDO) == -1)
		return -1;
	t(r = callback(NULL, user_data));
	if (!r)  goto done;
	for (;;) {
		t(release_semaphore(bus, Q, 0));
		t(zero_semaphore(bus, Q, 0));
		t(r = callback(bus->message, user_data));
		if (!r)  goto done;
		t(release_semaphore(bus, W, SEM_UNDO));  state++;
		t(acquire_semaphore(bus, S, SEM_UNDO));  state++;
		t(zero_semaphore(bus, S, 0));
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS_ME_HARDER
		t(zero_semaphore(bus, N, 0));
#endif
		t(release_semaphore(bus, S, SEM_UNDO));  state--;
		t(acquire_semaphore(bus, W, SEM_UNDO));  state--;
	}

fail:
	saved_errno = errno;
	if (state > 1)
		release_semaphore(bus, S, SEM_UNDO);
	if (state > 0)
		acquire_semaphore(bus, W, SEM_UNDO);
	acquire_semaphore(bus, S, SEM_UNDO);
	errno = saved_errno;
	return -1;

done:
	t(acquire_semaphore(bus, S, SEM_UNDO));
	return 0;
}
Example #10
0
File: bus.c Project: uselessd/bus
/**
 * Wait for a message to be broadcasted on the bus.
 * The caller should make a copy of the received message,
 * without freeing the original copy, and parse it in a
 * separate thread. When the new thread has started be
 * started, the caller of this function should then
 * either call `bus_poll_timed` again or `bus_poll_stop`.
 * 
 * @param   bus      Bus information
 * @param   timeout  The time the operation shall fail with errno set
 *                   to `EAGAIN` if not completed
 * @param   clockid  The ID of the clock the `timeout` is measured with,
 *                   it most be a predictable clock
 * @return           The received message, `NULL` on error
 */
const char *bus_poll_timed(bus_t *bus, const struct timespec *timeout, clockid_t clockid)
{
	int state = 0, saved_errno;
	struct timespec delta;
	if (!timeout)
		return bus_poll(bus, 0);

	if (!bus->first_poll) {
		t(release_semaphore(bus, W, SEM_UNDO));  state++;
		t(acquire_semaphore(bus, S, SEM_UNDO));  state++;
		t(zero_semaphore(bus, S, 0));
#ifndef BUS_SEMAPHORES_ARE_SYNCHRONOUS_ME_HARDER
		t(zero_semaphore(bus, N, 0));
#endif
		t(release_semaphore(bus, S, SEM_UNDO));  state--;
		t(acquire_semaphore(bus, W, SEM_UNDO));  state--;
		t(release_semaphore(bus, Q, 0));
	} else {
		bus->first_poll = 0;
	}
	state--;
	DELTA;
	t(zero_semaphore_timed(bus, Q, 0, &delta));
	return bus->message;

fail:
	saved_errno = errno;
	if (state > 1)
		release_semaphore(bus, S, SEM_UNDO);
	if (state > 0)
		acquire_semaphore(bus, W, SEM_UNDO);
	if (state < 0)
		bus->first_poll = 1;
	errno = saved_errno;
	return NULL;
}
Example #11
0
void
output_dump (struct output *out)
{
  int outfd_not_empty = FD_NOT_EMPTY (out->out);
  int errfd_not_empty = FD_NOT_EMPTY (out->err);

  if (outfd_not_empty || errfd_not_empty)
    {
      int traced = 0;

      /* Try to acquire the semaphore.  If it fails, dump the output
         unsynchronized; still better than silently discarding it.
         We want to keep this lock for as little time as possible.  */
      void *sem = acquire_semaphore ();

      /* Log the working directory for this dump.  */
      if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
        traced = log_working_directory (1);

      if (outfd_not_empty)
        pump_from_tmp (out->out, stdout);
      if (errfd_not_empty && out->err != out->out)
        pump_from_tmp (out->err, stderr);

      if (traced)
        log_working_directory (0);

      /* Exit the critical section.  */
      if (sem)
        release_semaphore (sem);

      /* Truncate and reset the output, in case we use it again.  */
      if (out->out != OUTPUT_NONE)
        {
          int e;
          lseek (out->out, 0, SEEK_SET);
          EINTRLOOP (e, ftruncate (out->out, 0));
        }
      if (out->err != OUTPUT_NONE && out->err != out->out)
        {
          int e;
          lseek (out->err, 0, SEEK_SET);
          EINTRLOOP (e, ftruncate (out->err, 0));
        }
    }
}
Example #12
0
int main() { 
    int rc;
    char s[1024];
    char last_message_i_wrote[256];
    char md5ified_message[256];
    int i = 0;
    int done = 0;
    struct param_struct params;
    int shm_id;
    void *address = NULL;
    int sem_id;
    struct shmid_ds shm_info;

    say(MY_NAME, "Oooo 'ello, I'm Mrs. Premise!");
    
    read_params(&params);
    
    // Create the shared memory
    shm_id = shmget(params.key, params.size, IPC_CREAT | IPC_EXCL | params.permissions);
    
    if (shm_id == -1) {
        shm_id = 0;
        sprintf(s, "Creating the shared memory failed; errno is %d", errno);
        say(MY_NAME, s);
    }
    else {
        sprintf(s, "Shared memory's id is %d", shm_id);
        say(MY_NAME, s);

        // Attach the memory.
        address = shmat(shm_id, NULL, 0);

        if ((void *)-1 == address) {
            address = NULL;
            sprintf(s, "Attaching the shared memory failed; errno is %d", errno);
            say(MY_NAME, s);
        }
        else {
            sprintf(s, "shared memory address = %p", address);
            say(MY_NAME, s);
        }
    }
    
    if (address) {
        // Create the semaphore
        sem_id = semget(params.key, 1, IPC_CREAT | IPC_EXCL | params.permissions);
    
        if (-1 == sem_id) {
            sem_id = 0;
            sprintf(s, "Creating the semaphore failed; errno is %d", errno);
            say(MY_NAME, s);
        }
        else {
            sprintf(s, "the semaphore id is %d", sem_id);
            say(MY_NAME, s);
        
            // I seed the shared memory with a random string (the current time).
            get_current_time(s);
    
            strcpy((char *)address, s);
            strcpy(last_message_i_wrote, s);

            sprintf(s, "Wrote %zu characters: %s", strlen(last_message_i_wrote), last_message_i_wrote);
            say(MY_NAME, s);
            
            i = 0;
            while (!done) {
                sprintf(s, "iteration %d", i);
                say(MY_NAME, s);

                // Release the semaphore...
                rc = release_semaphore(MY_NAME, sem_id, params.live_dangerously);
                // ...and wait for it to become available again. In real code 
                // I might want to sleep briefly before calling .acquire() in
                // order to politely give other processes an opportunity to grab
                // the semaphore while it is free so as to avoid starvation. But 
                // this code is meant to be a stress test that maximizes the 
                // opportunity for shared memory corruption and politeness is 
                // not helpful in stress tests.
                if (!rc)
                    rc = acquire_semaphore(MY_NAME, sem_id, params.live_dangerously);

                if (rc)
                    done = 1;
                else {
                    // I keep checking the shared memory until something new has 
                    // been written.
                    while ( (!rc) && \
                            (!strcmp((char *)address, last_message_i_wrote)) 
                          ) {
                        // Nothing new; give Mrs. Conclusion another change to respond.
                        sprintf(s, "Read %zu characters '%s'", strlen((char *)address), (char *)address);
                        say(MY_NAME, s);
                        rc = release_semaphore(MY_NAME, sem_id, params.live_dangerously);
                        if (!rc) {
                            rc = acquire_semaphore(MY_NAME, sem_id, params.live_dangerously);
                        }
                    }


                    if (rc) 
                        done = 1;
                    else {
                        sprintf(s, "Read %zu characters '%s'", strlen((char *)address), (char *)address);
                        say(MY_NAME, s);

                        // What I read must be the md5 of what I wrote or something's 
                        // gone wrong.
                        md5ify(last_message_i_wrote, md5ified_message);
                    
                        if (strcmp(md5ified_message, (char *)address) == 0) {
                            // Yes, the message is OK
                            i++;
                            if (i == params.iterations)
                                done = 1;

                            // MD5 the reply and write back to Mrs. Conclusion.
                            md5ify(md5ified_message, md5ified_message);
                            
                            sprintf(s, "Writing %zu characters '%s'", strlen(md5ified_message), md5ified_message);
                            say(MY_NAME, s);

                            strcpy((char *)address, md5ified_message);
                            strcpy((char *)last_message_i_wrote, md5ified_message);
                        }
                        else {
                            sprintf(s, "Shared memory corruption after %d iterations.", i);
                            say(MY_NAME, s);                            
                            sprintf(s, "Mismatch; new message is '%s', expected '%s'.", (char *)address, md5ified_message);
                            say(MY_NAME, s);
                            done = 1;
                        }
                    }
                }
            }

            // Announce for one last time that the semaphore is free again so that 
            // Mrs. Conclusion can exit.
            say(MY_NAME, "Final release of the semaphore followed by a 5 second pause");            
            rc = release_semaphore(MY_NAME, sem_id, params.live_dangerously);
            sleep(5);
            // ...before beginning to wait until it is free again. 
            // Technically, this is bad practice. It's possible that on a 
            // heavily loaded machine, Mrs. Conclusion wouldn't get a chance
            // to acquire the semaphore. There really ought to be a loop here
            // that waits for some sort of goodbye message but for purposes of
            // simplicity I'm skipping that.

            say(MY_NAME, "Final wait to acquire the semaphore");
            rc = acquire_semaphore(MY_NAME, sem_id, params.live_dangerously);
            if (!rc) {
                say(MY_NAME, "Destroying the shared memory.");
                
                if (-1 == shmdt(address)) {
                    sprintf(s, "Detaching the memory failed; errno is %d", errno);
                    say(MY_NAME, s);
                }
                address = NULL;
                
            
                if (-1 == shmctl(shm_id, IPC_RMID, &shm_info)) {
                    sprintf(s, "Removing the memory failed; errno is %d", errno);
                    say(MY_NAME, s);
                }
            }
        }

        say(MY_NAME, "Destroying the semaphore.");
        // Clean up the semaphore
        if (-1 == semctl(sem_id, 0, IPC_RMID)) {
            sprintf(s, "Removing the semaphore failed; errno is %d", errno);
            say(MY_NAME, s);
        }
    }
    return 0; 
}
/* Please see header for specification */
bool Anvil::Semaphore::reset()
{
    VkResult                                           result           (VK_ERROR_INITIALIZATION_FAILED);
    Anvil::StructChainer<VkSemaphoreCreateInfo>        struct_chainer;
    Anvil::StructChainUniquePtr<VkSemaphoreCreateInfo> struct_chain_ptr;

    release_semaphore();

    /* Sanity checks */
    if (m_create_info_ptr->get_exportable_external_semaphore_handle_types() != Anvil::ExternalSemaphoreHandleTypeFlagBits::NONE)
    {
        if (!m_device_ptr->get_extension_info()->khr_external_semaphore() )
        {
            anvil_assert(m_device_ptr->get_extension_info()->khr_external_semaphore() );

            goto end;
        }
    }

    /* Spawn a new semaphore */
    {
        VkSemaphoreCreateInfo semaphore_create_info;

        semaphore_create_info.flags = 0;
        semaphore_create_info.pNext = nullptr;
        semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;

        struct_chainer.append_struct(semaphore_create_info);
    }

    if (m_create_info_ptr->get_exportable_external_semaphore_handle_types() != Anvil::ExternalSemaphoreHandleTypeFlagBits::NONE)
    {
        VkExportSemaphoreCreateInfo create_info;

        create_info.handleTypes = m_create_info_ptr->get_exportable_external_semaphore_handle_types().get_vk();
        create_info.pNext       = nullptr;
        create_info.sType       = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR;

        struct_chainer.append_struct(create_info);
    }

    #if defined(_WIN32)
    {
        const Anvil::ExternalNTHandleInfo* nt_handle_info_ptr = nullptr;

        if (m_create_info_ptr->get_exportable_nt_handle_info(&nt_handle_info_ptr) )
        {
            VkExportSemaphoreWin32HandleInfoKHR handle_info;

            anvil_assert( nt_handle_info_ptr                                                                                                                   != nullptr);
            anvil_assert(((m_create_info_ptr->get_exportable_external_semaphore_handle_types() & Anvil::ExternalSemaphoreHandleTypeFlagBits::OPAQUE_WIN32_BIT) != 0)       ||
                         ((m_create_info_ptr->get_exportable_external_semaphore_handle_types() & Anvil::ExternalSemaphoreHandleTypeFlagBits::D3D12_FENCE_BIT)  != 0));

            handle_info.dwAccess    = nt_handle_info_ptr->access;
            handle_info.name        = (nt_handle_info_ptr->name.size() > 0) ? &nt_handle_info_ptr->name.at(0)
                                                                            : nullptr;
            handle_info.pAttributes = nt_handle_info_ptr->attributes_ptr;
            handle_info.pNext       = nullptr;
            handle_info.sType       = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR;

            struct_chainer.append_struct(handle_info);
        }
    }
    #endif

    struct_chain_ptr = struct_chainer.create_chain();
    if (struct_chain_ptr == nullptr)
    {
        anvil_assert(struct_chain_ptr != nullptr);

        goto end;
    }

    result = Anvil::Vulkan::vkCreateSemaphore(m_device_ptr->get_device_vk(),
                                              struct_chain_ptr->get_root_struct(),
                                              nullptr, /* pAllocator */
                                             &m_semaphore);

    anvil_assert_vk_call_succeeded(result);
    if (is_vk_call_successful(result) )
    {
        set_vk_handle(m_semaphore);
    }

end:
    return is_vk_call_successful(result);
}
Example #14
0
File: wait.c Project: amir9/longene
NTSTATUS SERVICECALL
NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal,
		IN HANDLE WaitableObjectHandle,
		IN BOOLEAN Alertable,
		IN PLARGE_INTEGER TimeOut OPTIONAL)
{
	PVOID signal_obj, wait_obj;
	struct dispatcher_header *signal_header;
	LARGE_INTEGER _timeout;
	MODE previous_mode;
	NTSTATUS status;

	ktrace("ObjectHandleToSignal %p, WaitableObjectHandle %p, Alertable %d\n",
			ObjectHandleToSignal, WaitableObjectHandle, Alertable);
	previous_mode = (unsigned long)TimeOut > TASK_SIZE ? KernelMode : UserMode;
	if(TimeOut){
		if (previous_mode == UserMode) {
			if (copy_from_user(&_timeout, TimeOut, sizeof(_timeout)))
				return STATUS_NO_MEMORY;
		} else
			_timeout = *TimeOut;
	}

	status = ref_object_by_handle(ObjectHandleToSignal, 0,
			NULL, KernelMode, &signal_obj, NULL);
	if (!NT_SUCCESS(status))
		return status;

	status = ref_object_by_handle(WaitableObjectHandle, SYNCHRONIZE,
			NULL, KernelMode, &wait_obj, NULL);
	if (!NT_SUCCESS(status)) {
		deref_object(signal_obj);
		return status;
	}

	signal_header = (struct dispatcher_header *)signal_obj;

	if (is_wine_object(signal_header->type)) {
		struct object *obj = (struct object*)signal_obj;
		unsigned int access = get_handle_access(process2eprocess(current_thread->process), WaitableObjectHandle);
		if (BODY_TO_HEADER(obj)->ops->signal)
			BODY_TO_HEADER(obj)->ops->signal(obj, access);
	}
	else
		switch (signal_header->type) {
			case EventNotificationObject:
			case EventSynchronizationObject:
				set_event(signal_obj, EVENT_INCREMENT, TRUE);
				break;

			case MutantObject:
				release_mutant(signal_obj, IO_NO_INCREMENT, FALSE, TRUE);
				break;

			case SemaphoreObject:
				release_semaphore(signal_obj, SEMAPHORE_INCREMENT, 1, TRUE);
				break;

			default:
				deref_object(signal_obj);
				deref_object(wait_obj);
				return STATUS_OBJECT_TYPE_MISMATCH;
		}

	if(TimeOut){
		status = wait_for_single_object(wait_obj,
				UserRequest, KernelMode, Alertable, &_timeout);
	} else {
		status = wait_for_single_object(wait_obj,
				UserRequest, KernelMode, Alertable, NULL);
	}	

	if (!NT_SUCCESS(status))
		goto out;

	if (TimeOut) {
		if (previous_mode == UserMode) {
			if (copy_to_user(TimeOut, &_timeout, sizeof(_timeout))) {
				status = STATUS_NO_MEMORY;
				goto out;
			}
		} else
			*TimeOut = _timeout;
	}

out:
	deref_object(signal_obj);
	deref_object(wait_obj);

	return status;
} /* end NtSignalAndWaitForSingleObject */