/** * 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; }
/** * 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; }
/** * 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(); }
/** * 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; }
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); } }
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 ); }
/** * 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; }
/** * 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; }
/** * 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; }
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)); } } }
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(¶ms); // 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); }
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 */