예제 #1
0
int
main(void)
{
	struct linked_list l = { .head = NULL };
	add_to_end(&l, 1);
	add_to_end(&l, 2);
	add_to_end(&l, 3);
	remove_from_end(&l);
	print_list(&l);
	free_list(&l);
	return 0;
}
예제 #2
0
파일: array-list.c 프로젝트: nishgoswami/c
int
main(void)
{
	struct array_list l = { .array = malloc(0), .num_elements = 0 };
	add_to_end(&l, 3);
	add_to_end(&l, 5.5);
	add_at_position(&l, 1, 0.0);
	remove_at_position(&l, 0);
	for (size_t i = 0; i < l.num_elements; i++) {
		printf("%lf\n", l.array[i]);	// should print 0.0, then 5.5
	}
	free(l.array);
	return 0;
}
예제 #3
0
static          Generic_list
copy_list(Generic_list list)
{
    Generic_list    list_copy;
    Generic_list_element *element;

    initialize_sorted_list(&list_copy, list.info->lt);
    element = list.info->pre_element.next;
    while (element != &list.info->post_element) {
        add_to_end(list_copy, element->pointer);
        element = element->next;
    }

    return list_copy;
}
예제 #4
0
/*
 *	monitor_msg - thread routine to monitor messages.
 */
void *
monitor_msg(
	void *vlibrary)
{
	int 		exit_status = 0;
	sigset_t 	signal_set;
	library_t 	*library = (library_t *)vlibrary;
	robo_event_t 		*current_event;
	struct sigaction 	sig_action;
	message_request_t 	*message, shutdown;
	enum sam_mess_type 	mtype;

	/* dummy up a shutdown message */
	(void) memset(&shutdown, 0, sizeof (message_request_t));
	(void) memset(&sig_action, 0, sizeof (struct sigaction));

	shutdown.mtype = MESS_MT_SHUTDOWN;
	/* LINTED constant truncated by assignment */
	shutdown.message.magic = MESSAGE_MAGIC;
	shutdown.message.command = MESS_CMD_SHUTDOWN;

	/*
	 * Should have been called with all signals blocked,
	 * now let sigemt be delivered and just exit when it is
	 */
	sig_action.sa_handler = sig_catch;
	sig_action.sa_flags = 0;
	(void) sigemptyset(&signal_set);
	(void) sigaddset(&signal_set, SIGEMT);
	(void) sigaction(SIGEMT, &sig_action, (struct sigaction *)NULL);
	(void) thr_sigsetmask(SIG_UNBLOCK, &signal_set, NULL);

	mutex_lock(&library->mutex);	/* wait for initialize */
	mutex_unlock(&library->mutex);

	message = (message_request_t *)SHM_REF_ADDR(library->un->dt.rb.message);
	if (thr_create(NULL, MD_THR_STK, stk_acs_response, (void *)library,
	    (THR_BOUND | THR_NEW_LWP | THR_DETACHED), NULL)) {
		sam_syslog(LOG_CRIT,
		    "Unable to start stk_acs_response thread: %m.");
		thr_exit(NULL);
	}

	/* Main loop */
	for (;;) {
		current_event = get_free_event(library);

		/*
		 * Zeroing the struct has the effect of initializing
		 * the mutex and the condition to USYNC_THREAD, just
		 * what we want
		 */
		(void) memset(current_event, 0, sizeof (robo_event_t));
		current_event->status.bits = REST_FREEMEM;

		/* Wait for a message */
		mutex_lock(&message->mutex);
		while (message->mtype == MESS_MT_VOID)
			cond_wait(&message->cond_r, &message->mutex);

		/* Copy the request into the event */
		current_event->request.message = message->message;
		mtype = message->mtype;	/* capture message type */

		message->mtype = MESS_MT_VOID;	/* release the message area */
		message->message.exit_id.pid = 0;
		cond_signal(&message->cond_i);	/* and wake up anyone waiting */
		mutex_unlock(&message->mutex);

		if (mtype == MESS_MT_APIHELP) {
			current_event->next = NULL;
			mutex_lock(&stk_acs_mutex);
			/*
			 * If the list is NULL, this will be the only
			 * entry on the list.  Set the head and last to current
			 */
			if (stk_acs_event_head == NULL) {
				stk_acs_event_head =
				    stk_acs_event_last = current_event;
				cond_signal(&stk_acs_cond);
			} else {
				/*
				 * If the head is not null, last points to the
				 * last entry on the list. Point last
				 * next to the current then set last = current
				 */
				stk_acs_event_last->next = current_event;
				stk_acs_event_last = current_event;
			}

			mutex_unlock(&stk_acs_mutex);
		} else {
			current_event->type = EVENT_TYPE_MESS;

			/*
			 * Put the event on the list and
			 * wake up the event handler
			 */
			add_to_end(library, current_event);
			if (message->mtype == MESS_MT_SHUTDOWN) {
				if (DBG_LVL(SAM_DBG_DEBUG))
					sam_syslog(LOG_DEBUG,
					"shutdown request:%s:%d.",
					    __FILE__, __LINE__);
				threads[STK_MSG_THREAD] = (thread_t)-1;
				thr_exit(&exit_status);
				/* NOTREACHED */
				return (NULL);
			}
		}
	}
}
예제 #5
0
/*
 *	get_media - get the media mounted.
 *
 * entry   -
 *	 drive->mutex should be held.  This mutex
 *	 can be released during processing, but will be held
 *	 on return.
 *
 * returns -
 *	 0 - ok
 *	 1 - some sort of error, dispose of event
 *		Note: The catalog mutex is held on this condition.
 *	 2 - event was requeued.
 *	 -1 - same as 1 cept that the drive should be downed
 *
 *	 in all cases, dev_ent activity count will be incremented.
 */
int
get_media(
	library_t *library,
	drive_state_t *drive,
	robo_event_t *event,		/* the event (can be NULL) */
	struct CatalogEntry *ce)	/* catalog entry to be loaded */
{
	char *d_mess = drive->un->dis_mes[DIS_MES_NORM];
	dev_ent_t *un = drive->un;
	int status = 0;

	mutex_lock(&un->mutex);
	INC_ACTIVE(un);
	mutex_unlock(&un->mutex);

	/* is the media is already mounted */
	if (drive->status.b.full && (un->slot == ce->CeSlot)) {
		if (DBG_LVL(SAM_DBG_DEBUG))
			sam_syslog(LOG_DEBUG, "get_media:(%d)%s:%d.",
			    un->eq, __FILE__, __LINE__);
	} else {			/* get the media loaded */
		/*
		 * Make sure the source storage element has media in it.
		 * If the element is empty, external requests
		 * will be put back on the library's work list with the
		 * hope that it will be picked up later. Internal
		 * requests will return an error to the caller. If the in_use
		 * flag is not set, then the slot is
		 * "really" empty and the request will be disposed of.
		 */
		if (DBG_LVL(SAM_DBG_TMOVE))
			sam_syslog(LOG_DEBUG, "get_media:(%d)%s:%d.",
			    un->eq, __FILE__, __LINE__);

		if (!(ce->CeStatus & CES_occupied)) {
			/* Should this be put back on the library's list? */
			if ((ce->CeStatus & CES_inuse) && event != NULL &&
			    event->type != EVENT_TYPE_INTERNAL &&
			    !event->status.b.dont_reque) {
				event->next = NULL;
				add_to_end(library, event);
				/* Do not dispose of event */
				return (RET_GET_MEDIA_REQUEUED);
			}

			if (DBG_LVL(SAM_DBG_TMOVE))
				sam_syslog(LOG_DEBUG, "get_media:(%d)%s:%d.",
				    un->eq, __FILE__, __LINE__);
			return (RET_GET_MEDIA_DISPOSE);

		} else {
			status &= ~CES_occupied;
			(void) CatalogSetFieldByLoc(library->un->eq, ce->CeSlot,
			    0, CEF_Status, status, CES_occupied);
		}

		if (drive->status.b.full) {

			mutex_lock(&un->mutex);
			un->status.bits |= DVST_UNLOAD;
			mutex_unlock(&un->mutex);

			/*
			 * Save off what information we know about this volume
			 * before we spin down the drive and clear out the un.
			 */
			memmove(un->i.ViMtype, sam_mediatoa(un->type),
			    sizeof (un->i.ViMtype));
			memmove(un->i.ViVsn, un->vsn, sizeof (un->i.ViVsn));
			un->i.ViEq = un->fseq;
			un->i.ViSlot = un->slot;
			un->i.ViPart = 0;

			if (un->status.b.ready) {
				(void) spin_drive(drive, SPINDOWN, NOEJECT);
				sprintf(d_mess, "unloading %s", un->vsn);
			}

			mutex_lock(&un->mutex);
			close_unit(un, &drive->open_fd);
			un->status.bits = (DVST_REQUESTED | DVST_PRESENT) |
			    (un->status.bits & DVST_CLEANING);
			clear_un_fields(un);
			mutex_unlock(&un->mutex);

#if defined(USEDISMOUNT)
			sprintf(d_mess, "dismounting %s", un->vsn);
			if (dismount_media(library, drive) != MC_REQ_OK) {
				if (DBG_LVL(SAM_DBG_TMOVE))
					sam_syslog(LOG_DEBUG,
					    "get_media:(%d)%s:%d.",
					    un->eq, __FILE__, __LINE__);
				return (RET_GET_MEDIA_DOWN_DRIVE);
			}
#endif					/* defined(USEDISMOUNT) */


			/* clean up the old entries */
			if (*un->i.ViMtype != '\0')
				un->i.ViFlags |= VI_mtype;
			if (*un->i.ViVsn != '\0')
				un->i.ViFlags |= VI_vsn;
			CatalogVolumeUnloaded(&un->i, "");

			mutex_lock(&un->mutex);
			un->slot = ROBOT_NO_SLOT;
			un->mid = un->flip_mid = ROBOT_NO_SLOT;
			un->label_time = 0;
			mutex_unlock(&un->mutex);

			/* clear the drive information */
			drive->status.b.full = FALSE;
			drive->status.b.bar_code = FALSE;
		}
#if !defined(USEDISMOUNT)
		if (*un->i.ViVsn != '\0')
			sprintf(d_mess, "dismount %s/mount %s",
			    un->i.ViVsn, un->vsn);
		else
			sprintf(d_mess, "mount %s", ce->CeVsn);
#else
		sprintf(d_mess, "mount %s", ce->CeVsn);
#endif
		if (load_media(library, drive, ce, 0) != MC_REQ_OK) {
			/*
			 * Process error and return status to caller.
			 * Requeue the event if not internal otherwise
			 * return status to caller.
			 */
			req_comp_t err;
			int ret = RET_GET_MEDIA_DISPOSE;
			IBM_query_info_t *info;
			if (DBG_LVL(SAM_DBG_DEBUG))
				sam_syslog(LOG_DEBUG, "load of %s failed.",
				    ce->CeVsn);

			sprintf(d_mess, "mount of %s failed.", ce->CeVsn);
			if (DBG_LVL(SAM_DBG_TMOVE))
				sam_syslog(LOG_DEBUG, "get_media:(%d)%s:%d.",
				    un->eq, __FILE__, __LINE__);

			/*
			 * Attempt some sort of recovery:
			 * Check the state of the volume itself
			 */
			err = view_media(library, ce->CeBarCode, (void *)&info);
			if (err != MC_REQ_OK) {

				status |= CES_occupied;
				(void) CatalogSetFieldByLoc(library->un->eq,
				    ce->CeSlot, 0, CEF_Status, status, 0);

				/* If internal event, then dont requeue it */
				if (event == NULL ||
				    event->type == EVENT_TYPE_INTERNAL)
					ret = RET_GET_MEDIA_DISPOSE;
			} else if (info != NULL) {
				ushort_t vol_status, category;

				memcpy(&vol_status, &info->
				    data.expand_vol_data.volume_status[0],
				    sizeof (vol_status));
				memcpy(&category,
				    &info->data.expand_vol_data.cat_assigned[0],
				    sizeof (category));
				if (vol_status & MT_VLI)
					sam_syslog(LOG_INFO, "get_media(%d):"
					    " %s Present but inaccessible.",
					    LIBEQ, ce->CeVsn);
				if (vol_status & (MT_VM | MT_VQM | MT_VPM |
				    MT_VQD | MT_VPD))
					sam_syslog(LOG_INFO, "get_media(%d):"
					    " %s, Mounting/Dismounting "
					    " or queued.", LIBEQ, ce->CeVsn);
				if (vol_status & (MT_VQE | MT_VPE))
					sam_syslog(LOG_INFO, "get_media(%d):"
					    " %s, Ejecting.", LIBEQ,
					    ce->CeVsn);
				if (vol_status & MT_VMIS)
					sam_syslog(LOG_INFO, "get_media(%d):"
					    " %s, Misplaced.", LIBEQ,
					    ce->CeVsn);
				if (vol_status & MT_VUU)
					sam_syslog(LOG_INFO, "get_media(%d):"
					    " %s, Unreadable label.", LIBEQ,
					    ce->CeVsn);
				if (vol_status & MT_VMM)
					sam_syslog(LOG_INFO, "get_media(%d):"
					    " %s, Used during manual mode.",
					    LIBEQ, ce->CeVsn);
				if (vol_status & MT_VME)
					sam_syslog(LOG_INFO, "get_media(%d):"
					    " %s, Manually Ejected.",
					    LIBEQ, ce->CeVsn);
				if (category == MAN_EJECTED_CAT)
					set_media_category(library, ce->CeVsn,
					    MAN_EJECTED_CAT,
					    PURGE_VOL_CATEGORY);
				if (vol_status & (MT_VLI | MT_VQE | MT_VPE |
				    MT_VMIS | MT_VUU | MT_VME)) {
					ret = RET_GET_MEDIA_DISPOSE;
					sam_syslog(LOG_INFO,
					    "rec_cat(%d): %s, ce->CeSlot %d:"
					    " removed from catalog",
					    LIBEQ, ce->CeVsn, ce->CeSlot);
				}
				free(info);
			}
			return (ret);
		}
	}

	mutex_lock(&un->mutex);
	drive->status.b.full = TRUE;
	drive->status.b.valid = TRUE;
	memmove(un->vsn, ce->CeVsn, sizeof (un->vsn));
	un->slot = ce->CeSlot;
	un->mid = ce->CeMid;
	un->flip_mid = ROBOT_NO_SLOT;
	un->status.b.labeled = FALSE;
	un->status.b.ready = FALSE;
	drive->status.b.bar_code = TRUE;
	memcpy(drive->bar_code, ce->CeBarCode, BARCODE_LEN + 1);
	un->space = ce->CeSpace;
	switch (un->type & DT_CLASS_MASK) {
	case DT_OPTICAL:
		un->dt.od.ptoc_fwa = ce->m.CePtocFwa;
		break;

	case DT_TAPE:
		un->dt.tp.position = ce->m.CeLastPos;
		break;
	}
	mutex_unlock(&un->mutex);

	return (RET_GET_MEDIA_SUCCESS);
}
예제 #6
0
static void
listAppend(UtilList * ul, const void *elm)
{
    Generic_list    l = *(Generic_list *) & ul->hdl;
    add_to_end(l, (void *) elm);
}
예제 #7
0
void *
manage_list(void *vlibrary)
{
	int			exit_status = 0, old_count;
	char			*ent_pnt = "manage_list";
	ushort_t		delayed;
	time_t			now, short_delay, auto_check;
	robo_event_t		*current, *next;
	library_t		*library = (library_t *)vlibrary;

	mutex_lock(&library->mutex);    /* wait for initialization */
	mutex_unlock(&library->mutex);

	short_delay = 0;
	old_count = 0;
	delayed = 0;
	auto_check = (time(&now) + 5);

	for (;;) {
		mutex_lock(&library->list_mutex);

		/*
		 * See if there in anything to do.  We will wait if the
		 * active count is 0 or its equal to the same value it had
		 * when we last woke up and there is a delayed request.
		 */
		if (library->active_count == 0 ||
		    ((old_count == library->active_count) && delayed)) {

			timestruc_t	wait_time;

			wait_time.tv_sec = time(&now) + library->un->delay;
			wait_time.tv_nsec = 0;
			if ((auto_check >= now) &&
			    (auto_check <  wait_time.tv_sec))

				wait_time.tv_sec = auto_check;

			if (delayed && (short_delay < wait_time.tv_sec))
				wait_time.tv_sec = short_delay;

			if (wait_time.tv_sec > now) {
				cond_timedwait(&library->list_condit,
				    &library->list_mutex, &wait_time);
				if (library->chk_req) {
					library->chk_req = FALSE;
					if (library->un->state == DEV_ON)
						/*
						 * Force a check
						 */
						auto_check = 0;
				}
			}
		}

		/*
		 * Get the current time
		 */
		time(&now);
		if (auto_check <= now) {
			mutex_unlock(&library->list_mutex);
			(void) check_requests(library);
			auto_check = now + library->un->delay;
			continue;
		}

		/*
		 * If there is something on the list . . .
		 */
		if ((old_count = library->active_count) == 0) {
			mutex_unlock(&library->list_mutex);
			continue;
		}

		short_delay = 0;
		delayed = FALSE;
		current = library->first;
		mutex_unlock(&library->list_mutex);

		do {
			mutex_lock(&library->list_mutex);
			/*
			 * If delayed and the time has not expired,
			 * go on tothe next
			 */
			next = current->next;
			if ((current->status.b.delayed) &&
			    (current->timeout > now)) {

				if (short_delay == 0)
					short_delay = current->timeout;
				else if (current->timeout < short_delay)
					short_delay = current->timeout;
				current = next;
				/*
				 * Need to know there are delayed requests
				 */
				delayed = TRUE;

				mutex_unlock(&library->list_mutex);
				continue;
			}

			if (current == library->first)
				library->first = unlink_list(current);
			else
				(void) unlink_list(current);

			current->next = NULL;
			ETRACE((LOG_NOTICE, "LbEv c %#x n %#x (%d)\n", current,
			    library->first, library->active_count));
			library->active_count--;
			library->un->active = library->active_count;
			mutex_unlock(&library->list_mutex);

			/*
			 * Entry is off the list and ready to process
			 */
			switch (current->type) {
			case EVENT_TYPE_INTERNAL:

				switch (current->request.internal.command) {

				case ROBOT_INTRL_AUDIT_SLOT:
					if (start_audit(library, current,
					    current->request.internal.slot)) {
						/*
						 * Unable to find resources,
						 * delay the request and try
						 * later
						 */
						current->status.b.delayed
						    = TRUE;
						current->timeout = now + 10;
						delayed = TRUE;
						add_to_end(library, current);
					}
					current = next;
					break;

				default:
					sam_syslog(LOG_ERR,
					    "%s:Bad internal event: %s:%d\n",
					    ent_pnt, __FILE__, __LINE__);

					break;
				}

				break;

			case EVENT_TYPE_MESS:
				if (current->request.message.magic
				    != MESSAGE_MAGIC) {
					sam_syslog(LOG_ERR,
					    "%s: Bad magic %#x.", ent_pnt,
					    current->request.message.magic);
					current->completion = EAGAIN;
					disp_of_event(library, current, EBADF);
					current = next;
					continue;
				}
				if (library->un->state >= DEV_OFF &&
				    (current->request.message.command >
				    ACCEPT_DOWN)) {

					current->completion = EAGAIN;
					disp_of_event(library, current, EAGAIN);
					current = next;
					continue;
				}

			switch (current->request.message.command) {

				case MESS_CMD_SHUTDOWN:
					if (DBG_LVL(SAM_DBG_DEBUG))
						sam_syslog(LOG_DEBUG,
						    "received"
						    " shutdown:%s:%d.\n",
						    __FILE__, __LINE__);
					post_shutdown(library);
					threads[SONY_WORK_THREAD]
					    = (thread_t)-1;
					thr_exit(&exit_status);
					break;

				case MESS_CMD_STATE:
					/*
					 * state_request will put the event
					 * back on the free list when
					 * the command is done.
					 */
					state_request(library, current);
					current = next;
					break;

				case MESS_CMD_TAPEALERT:
					/*
					 * tapealert_request will put the
					 * event back on the
					 * free list when the command is done.
					 */
					tapealert_solicit(library, current);
					current = next;
					break;

				case MESS_CMD_SEF:
					/*
					 * sef_request will put the event
					 * back on the free list when the
					 * command is done.
					 */
					sef_solicit(library, current);
					current = next;
					break;

				case MESS_CMD_LABEL:
					if (label_request(library, current)) {
						/*
						 * Unable to find resources,
						 * delay the request, try later.
						 */
						current->status.b.delayed
						    = TRUE;
						current->timeout = now + 10;
						delayed = TRUE;
						add_to_end(library, current);
					}
					current = next;
					break;

				case MESS_CMD_MOUNT:
					/*
					 * mount_request will take care of
					 * putting the event back on free list
					 */
					if (mount_request(library, current)) {
						/*
						 * Unable to find resources,
						 * delay request and try later.
						 */
						current->status.b.delayed
						    = TRUE;
						current->timeout = now + 10;
						delayed = TRUE;
						add_to_end(library, current);
					}
					current = next;
					break;

				case MESS_CMD_LOAD_UNAVAIL:
					load_unavail_request(library, current);
					current = next;
					break;

				case MESS_CMD_AUDIT:
				if (start_audit(library, current, current->
				    request.message.param.audit_request.slot)) {
						current->status.b.delayed
						    = TRUE;
						current->timeout = now + 10;
						delayed = TRUE;
						add_to_end(library, current);
					}
					current = next;
					break;

				case MESS_CMD_PREVIEW:
					(void) check_requests(library);
					time(&now);
					auto_check = now + library->un->delay;
					disp_of_event(library, current, 0);
					current = next;
					break;

				case MESS_CMD_UNLOAD:
					/*
					 * unload_request will put the event
					 * back on the free list when
					 * the command is done.
					 * unload_request will add the request
					 * to the drive's worklist.
					 */
					unload_request(library, current);
					current = next;
					break;

				case MESS_CMD_TODO:
					todo_request(library, current);
					current = next;
					break;

				case MESS_CMD_ADD:
					add_to_cat_req(library, current);
					current = next;
					break;

				case MESS_CMD_EXPORT:
					/*
					 * export_request will add the request
					 * to the
					 * mailbox worklist.
					 */
					export_media(library, current);
					current = next;
					break;

				case MESS_CMD_ACK:
					/*
					 * A no-op. Dispose of event.
					 */
					disp_of_event(library, current, 0);
					current = next;
					break;

				default:
					sam_syslog(LOG_ERR,
					    "%s: Unknown robot command %d.",
					    ent_pnt,
					    current->request.message.command);

					disp_of_event(library, current, 0);
					current = next;
					break;
				}

			break;

			default:
				sam_syslog(LOG_ERR,
				    "%s: Unknown event type %d.\n",
				    ent_pnt, current->type);
				disp_of_event(library, current, EBADF);
				current = next;
				break;
			}
			break;
		} while (current != NULL);
	}
}