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; }
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; }
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; }
/* * 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); } } } }
/* * 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); }
static void listAppend(UtilList * ul, const void *elm) { Generic_list l = *(Generic_list *) & ul->hdl; add_to_end(l, (void *) elm); }
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); } }