示例#1
0
文件: bus.c 项目: 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;
}
示例#2
0
文件: bus.c 项目: 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;
}
示例#3
0
static int dpram_write_full(struct modemctl *mc,
                            char __user *firmware, int size)
{
    struct onedram_head_t onedram;
    u32 data_offset = ONEDRAM_DL_DATA_OFFSET;
    u32 head_offset = ONEDRAM_DL_HEADER_OFFSET;
    u32 checksum;

    pr_debug("%s\n", __func__);

    acquire_semaphore(mc);

    /* write full data of firmware */
    dpram_write_from_user(mc, data_offset, firmware, size);
    /* check checksum */
    checksum = onedram_checksum(0, (u8 *)(mc->mmio + data_offset), size);

    onedram.signature	= ONEDRAM_DL_SIGNATURE;
    onedram.is_boot_update	= 0;
    onedram.is_nv_update	= 0;
    onedram.length		= size;
    onedram.checksum	= checksum;

    /* write header info */
    memcpy(mc->mmio + head_offset, (u8 *)&onedram, sizeof(onedram));

    return 0;
}
示例#4
0
文件: bus.c 项目: 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;
}
示例#5
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);
    }
}
示例#6
0
static int dpram_write_delta(struct modemctl *mc,
                             char __user *firmware, int size)
{
    int ret = 0;

    pr_debug("%s\n", __func__);
    acquire_semaphore(mc);
    /* write the sizeof firmware */
    write_single_data(mc, DPRAM_FIRMWARE_SIZE_ADDR, size);
    /* write the data of firmware */
    dpram_write_from_user(mc, DPRAM_FIRMWARE_ADDR, firmware, size);
    return ret;
}
示例#7
0
文件: bus.c 项目: 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;

}
示例#8
0
static int dpram_update_delta(struct modemctl *mc)
{
    int err = 0;
    int msec = 0;
    u32 val;

    pr_debug("%s\n", __func__);

    acquire_semaphore(mc);
    /* write boot magic */
    write_single_data(mc, DPRAM_BOOT_MAGIC_ADDR,
                      DPRAM_BOOT_MAGIC_RECOVERY_FOTA);
    write_single_data(mc, DPRAM_BOOT_TYPE_ADDR,
                      DPRAM_BOOT_TYPE_DPRAM_DELTA);
    /* At this point modem is powered off.  So power on modem */
    err = dpram_modem_pwron(mc);
    if (err < 0) {
        pr_err("modem_reset() fail : %d", modem_pwr_status(mc));
        return err;
    }
    /* clear mailboxBA */
    set_mailbox_ba(mc, 0xFFFFFFFF);
    /* wait for job sync message */
    while (true) {
        val = get_mailbox_ab(mc);
        if ((val & STATUS_JOB_MAGIC_M) == STATUS_JOB_MAGIC_CODE) {
            err = 0;
            break;
        }
        msleep(1);
        if (++msec > 20000) {
            err = -2;
            pr_err("Failed to sync with modem (%x)", val);
            return err;
        }
        if ((msec % 1000) == 0)
            pr_info("Waiting for sync message... 0x%08x (pwr:%s)", \
                    val, modem_pwr_status(mc) ? "ON" : "OFF");
    }
    if (err == 0) {
        pr_info("Modem ready to start the firmware update");
        /* let modem start the job */
        set_mailbox_ba(mc, STATUS_JOB_MAGIC_CODE);
        /* If we have the semaphore, toss it to modem. */
        return_semaphore(mc);
    }

    return err;

}
示例#9
0
文件: bus.c 项目: 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;
}
示例#10
0
文件: bus.c 项目: 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;
}
示例#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));
        }
    }
}
示例#12
0
static int dpram_chk_full_update(struct modemctl *mc,
                                 int __user *pct, char __user *msg)
{
    int err;
    u32 status = 0;
    u32 phone_active = 0;
    bool is_reboot = 0;

    err = 3;
    mc->dpram_prev_status = 0xFFFFFFFF;
    mc->dpram_prev_phone_active = 0xFFFFFFFF;

retry:
    phone_active = modem_pwr_status(mc);
    status = get_mailbox_ab(mc);

    pr_debug("PHONE %d Mailbox 0x%x\n", phone_active, status);
    if ((mc->dpram_prev_phone_active != phone_active) ||
            (mc->dpram_prev_status != status)) {
        mc->dpram_prev_phone_active = phone_active;
        mc->dpram_prev_status = status;
    }

    if (!phone_active) {
        if (status == ONEDRAM_DL_COMPLETE) {
            pr_info("*OK* ONEDRAM_DL_COMPLETE\n");
            err = 0;
        } else if (status == ONEDRAM_DL_DONE_AND_RESET) {
            pr_info("*OK* ONEDRAM_DONE_AND_RESET\n");
            dpram_modem_pwron(mc);
            goto retry;
        }
    }

    if (status == ONEDRAM_DL_CHECKSUM_ERR) {
        pr_info("*ERROR* ONEDRAM_DL_CHECKSUM_ERR\n");
        is_reboot = 1;
    } else if (status == ONEDRAM_DL_ERASE_WRITE_ERR) {
        pr_info("*ERROR* ONEDRAM_DL_ERASE_WRITE_ERR\n");
        is_reboot = 1;
    } else if (status == ONEDRAM_DL_BOOT_UPDATE_ERR) {
        pr_info("*ERROR* ONEDRAM_DL_BOOT_UPDATE_ERR\n");
        is_reboot = 1;
    } else if (status == ONEDRAM_DL_REWRITE_FAIL_ERR) {
        pr_info("*ERROR* ONEDRAM_DL_REWRITE_FAIL_ERR\n");
        is_reboot = 1;
    } else if (status == ONEDRAM_DL_LENGTH_CH_FAIL) {
        pr_info("*ERROR* ONEDRAM_DL_LENGTH_CH_FAIL\n");
        is_reboot = 1;
    } else {
        if (status != mc->dpram_prev_status)
            pr_info("*ERROR* %d, 0x%x\n", phone_active, status);
    }

    if (is_reboot) {
        pr_info("system reboot necessary\n");
        err = -1;
    }

    if (err <= 0) {
        pr_info("Update done.\n");
        acquire_semaphore(mc);
        write_single_data(mc, 0, 0xffffffff);
    }

    return err;
}
示例#13
0
文件: bus.c 项目: uselessd/bus
/**
 * Announce that the thread has stopped listening on the bus.
 * This is required so that the thread does not cause others
 * to wait indefinitely.
 * 
 * @param   bus  Bus information
 * @return       0 on success, -1 on error
 */
int
bus_poll_stop(const bus_t *bus)
{
	return acquire_semaphore(bus, S, SEM_UNDO | IPC_NOWAIT);
}
示例#14
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; 
}