static void *attempt_thread(void *data) { struct outgoing *o = data; int res, reason; if (!ast_strlen_zero(o->app)) { if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries); res = ast_pbx_outgoing_app(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->app, o->data, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL); } else { if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for %s@%s:%d (Retry %d)\n", o->tech, o->dest, o->exten, o->context,o->priority, o->retries); res = ast_pbx_outgoing_exten(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->context, o->exten, o->priority, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL); } if (res) { ast_log(LOG_NOTICE, "Call failed to go through, reason %d\n", reason); if (o->retries >= o->maxretries + 1) { /* Max retries exceeded */ ast_log(LOG_EVENT, "Queued call to %s/%s expired without completion after %d attempt%s\n", o->tech, o->dest, o->retries - 1, ((o->retries - 1) != 1) ? "s" : ""); remove_from_queue(o, "Expired"); } else { /* Notate that the call is still active */ safe_append(o, time(NULL), "EndRetry"); } } else { ast_log(LOG_NOTICE, "Call completed to %s/%s\n", o->tech, o->dest); ast_log(LOG_EVENT, "Queued call to %s/%s completed\n", o->tech, o->dest); remove_from_queue(o, "Completed"); } free_outgoing(o); return NULL; }
static int scan_service(char *fn, time_t now, time_t atime) { struct outgoing *o; FILE *f; o = malloc(sizeof(struct outgoing)); if (o) { init_outgoing(o); f = fopen(fn, "r+"); if (f) { if (!apply_outgoing(o, fn, f)) { #if 0 printf("Filename: %s, Retries: %d, max: %d\n", fn, o->retries, o->maxretries); #endif fclose(f); if (o->retries <= o->maxretries) { now += o->retrytime; if (o->callingpid && (o->callingpid == ast_mainpid)) { safe_append(o, time(NULL), "DelayedRetry"); ast_log(LOG_DEBUG, "Delaying retry since we're currently running '%s'\n", o->fn); free_outgoing(o); } else { /* Increment retries */ o->retries++; /* If someone else was calling, they're presumably gone now so abort their retry and continue as we were... */ if (o->callingpid) safe_append(o, time(NULL), "AbortRetry"); safe_append(o, now, "StartRetry"); launch_service(o); } return now; } else { ast_log(LOG_EVENT, "Queued call to %s/%s expired without completion after %d attempt%s\n", o->tech, o->dest, o->retries - 1, ((o->retries - 1) != 1) ? "s" : ""); free_outgoing(o); remove_from_queue(o, "Expired"); return 0; } } else { free_outgoing(o); ast_log(LOG_WARNING, "Invalid file contents in %s, deleting\n", fn); fclose(f); remove_from_queue(o, "Failed"); } } else { free_outgoing(o); ast_log(LOG_WARNING, "Unable to open %s: %s, deleting\n", fn, strerror(errno)); remove_from_queue(o, "Failed"); } } else ast_log(LOG_WARNING, "Out of memory :(\n"); return -1; }
// Give up the CPU for one scheduling round. void yield(void) { //cprintf("yield...\n"); acquire(&ptable.lock); //DOC: yieldlock proc->state = RUNNABLE; // Loop thru pstat.pid to find the slot number in ptable. int slot_no; // slot idx for (slot_no = 0; slot_no < NPROC; ++slot_no) if (proc_stat.pid[slot_no] == proc->pid) break; //assert(i < NPROC); if (slot_no == NPROC) cprintf("slot_no == NPROC\n"); int pri = proc_stat.priority[slot_no]; ++proc_stat.ticks[slot_no][pri]; //cprintf("pid: %d have used %d timerticks.\n", //proc->pid, proc_stat.ticks[slot_no][pri]); // Updates priority queues here. if (proc_stat.ticks[slot_no][pri] == tick_bounds(pri) || (pri == 3 && proc_stat.ticks[slot_no][pri] % 8 == 0)) { switch (pri) { case 0: //cprintf("pri 0 to pri 1.\n"); remove_from_queue(&q0_head, &q0_tail, proc); append_to_queue(&q1_head, &q1_tail, proc); proc_stat.priority[slot_no] = 1; break; case 1: //cprintf("pri 1 to pri 2.\n"); remove_from_queue(&q1_head, &q1_tail, proc); append_to_queue(&q2_head, &q2_tail, proc); proc_stat.priority[slot_no] = 2; break; case 2: //cprintf("pri 2 to pri 3.\n"); remove_from_queue(&q2_head, &q2_tail, proc); append_to_queue(&q3_head, &q3_tail, proc); proc_stat.priority[slot_no] = 3; break; case 3: // RR //cprintf("RR here.\n"); remove_from_queue(&q3_head, &q3_tail, proc); append_to_queue(&q3_head, &q3_tail, proc); break; default: cprintf("Wrong priority.\n"); } } sched(); release(&ptable.lock); }
/* Go through the pending queue for the indicated semaphore * looking for tasks that can be completed. */ static void update_queue (struct sem_array * sma) { int error; struct sem_queue * q; for (q = sma->sem_pending; q; q = q->next) { if (q->status == 1) continue; /* this one was woken up before */ error = try_atomic_semop(sma, q->sops, q->nsops, q->undo, q->pid, q->alter); /* Does q->sleeper still need to sleep? */ if (error <= 0) { /* Found one, wake it up */ wake_up_process(q->sleeper); if (error == 0 && q->alter) { /* if q-> alter let it self try */ q->status = 1; return; } q->status = error; remove_from_queue(sma,q); } } }
int setpriority(int pid,int new_priority){ struct proc *p; int found = -1; acquire(&ptable.lock); // Scan through table looking for the process with the specified pid for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ if(p->pid == pid){ acquire(&runqueue.lock); remove_from_queue( p->pid, p->priority ); cprintf("set priority of proc %d from %d to %d\n", p->pid,p->priority, new_priority); p->priority = new_priority; release(&runqueue.lock); found = 0; break; } } release(&ptable.lock); return found; }
/* Go through the pending queue for the indicated semaphore * looking for tasks that can be completed. */ static void update_queue (struct semid_ds * sma) { int error; struct sem_queue * q; for (q = sma->sem_pending; q; q = q->next) { if (q->status == 1) return; /* wait for other process */ error = try_atomic_semop(sma, q->sops, q->nsops, q->undo, q->pid, q->alter); /* Does q->sleeper still need to sleep? */ if (error <= 0) { /* Found one, wake it up */ wake_up_interruptible(&q->sleeper); if (error == 0 && q->alter) { /* if q-> alter let it self try */ q->status = 1; return; } q->status = error; remove_from_queue(sma,q); } } }
//Given a queue try to pull some items off //Let's abuse the things we were given //Use the queue as a list, order doesn't matter. Why rewrite code; //Return queue of strings, and the number of items in there queue_t * get_items(queue_t * queue, unsigned int num_items, unsigned int * num_returned) { //Allocate a queue queue_t * ret_queue = create_queue(); //Remove elements until reaching null or the number requested *num_returned = 0; #pragma omp critical { while(1) { //Try to remove an item queue_element_t * item = remove_from_queue(queue); if(item == NULL) { break; } //Add this item to the queue insert_in_queue(ret_queue, item); *num_returned = *num_returned +1; if(*num_returned >=num_items) { break; } } } //printf("Got %u/%u from queue\n", *num_returned, num_items); return ret_queue; }
uint64_t syscall_kill(int32_t option, int32_t pid) { if (pid == 0 || pid == 1) { printf("-sbush: kill(%d): Not allowed\n", pid); return -1; } struct process_queue *iter = pqueue; struct process_queue *item = NULL; while (iter) { if (iter->proc.pid == pid) { item = iter; break; } iter = iter->next; } if (item) { remove_from_queue(&pqueue, item); resume_wait_proc(item->proc.pid); if (curr_task->proc.parent_fg == &item->proc) { curr_task->proc.parent_fg = item->proc.parent_fg; } cleanup_task(item); return 0; } iter = wqueue; while (iter) { if (iter->proc.pid == pid) { item = iter; break; } iter = iter->next; } if (item) { remove_from_queue(&wqueue, item); resume_wait_proc(item->proc.pid); if (curr_task->proc.parent_fg == &item->proc) { curr_task->proc.parent_fg = item->proc.parent_fg; } cleanup_task(item); return 0; } printf("-sbush: kill(%d): No such process\n", pid); return 0; }
int __pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, const struct timespec *abstime) { pthread_descr self; pthread_extricate_if extr; if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) return EINVAL; self = thread_self (); /* Set up extrication interface */ extr.pu_object = rwlock; extr.pu_extricate_func = rwlock_wr_extricate_func; /* Register extrication interface */ __pthread_set_own_extricate_if (self, &extr); while(1) { __pthread_lock (&rwlock->__rw_lock, self); if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL) { rwlock->__rw_writer = self; __pthread_set_own_extricate_if (self, 0); __pthread_unlock (&rwlock->__rw_lock); return 0; } /* Suspend ourselves, then try again */ enqueue (&rwlock->__rw_write_waiting, self); __pthread_unlock (&rwlock->__rw_lock); /* This is not a cancellation point */ if (timedsuspend (self, abstime) == 0) { int was_on_queue; __pthread_lock (&rwlock->__rw_lock, self); was_on_queue = remove_from_queue (&rwlock->__rw_write_waiting, self); __pthread_unlock (&rwlock->__rw_lock); if (was_on_queue) { __pthread_set_own_extricate_if (self, 0); return ETIMEDOUT; } /* Eat the outstanding restart() from the signaller */ suspend (self); } } }
static int rwlock_wr_extricate_func(void *obj, pthread_descr th) { pthread_rwlock_t *rwlock = obj; int did_remove = 0; __pthread_lock(&rwlock->__rw_lock, NULL); did_remove = remove_from_queue(&rwlock->__rw_write_waiting, th); __pthread_unlock(&rwlock->__rw_lock); return did_remove; }
static int _cancel_net_timer(net_timer_event *e) { if(!e->pending) { return ERR_GENERAL; } remove_from_queue(e); e->pending = false; return NO_ERROR; }
static int new_sem_extricate_func(void *obj, pthread_descr th) { __volatile__ pthread_descr self = thread_self(); sem_t *sem = obj; int did_remove = 0; __pthread_lock(&sem->__sem_lock, self); did_remove = remove_from_queue(&sem->__sem_waiting, th); __pthread_unlock(&sem->__sem_lock); return did_remove; }
/* * add semadj values to semaphores, free undo structures. * undo structures are not freed when semaphore arrays are destroyed * so some of them may be out of date. * IMPLEMENTATION NOTE: There is some confusion over whether the * set of adjustments that needs to be done should be done in an atomic * manner or not. That is, if we are attempting to decrement the semval * should we queue up and wait until we can do so legally? * The original implementation attempted to do this (queue and wait). * The current implementation does not do so. The POSIX standard * and SVID should be consulted to determine what behavior is mandated. */ void sem_exit (void) { struct sem_queue *q; struct sem_undo *u, *un = NULL, **up, **unp; struct semid_ds *sma; int nsems, i; /* If the current process was sleeping for a semaphore, * remove it from the queue. */ if ((q = current->semsleeping)) { if (q->prev) remove_from_queue(q->sma,q); current->semsleeping = NULL; } for (up = ¤t->semundo; (u = *up); *up = u->proc_next, kfree(u)) { if (u->semid == -1) continue; sma = semary[(unsigned int) u->semid % SEMMNI]; if (sma == IPC_UNUSED || sma == IPC_NOID) continue; if (sma->sem_perm.seq != (unsigned int) u->semid / SEMMNI) continue; /* remove u from the sma->undo list */ for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { if (u == un) goto found; } printk ("sem_exit undo list error id=%d\n", u->semid); break; found: *unp = un->id_next; /* perform adjustments registered in u */ nsems = sma->sem_nsems; for (i = 0; i < nsems; i++) { struct sem * sem = &sma->sem_base[i]; sem->semval += u->semadj[i]; if (sem->semval < 0) sem->semval = 0; /* shouldn't happen */ sem->sempid = current->pid; } sma->sem_otime = CURRENT_TIME; /* maybe some queued-up processes were waiting for this */ update_queue(sma); } current->semundo = NULL; }
bool Resource::erase(Arrival* arrival, bool stay) { if (stay) { int amount = remove_from_server(false, sim->now(), arrival, -1); server_count += amount; return false; } if (!remove_from_queue(sim->verbose, sim->now(), arrival)) { release(arrival, -1); return false; } if (is_monitored()) sim->record_resource(name, server_count, queue_count, capacity, queue_size); return true; }
//Given dirs just for this thread and global file queue void process_dirs(queue_t * loc_dir_queue, queue_t * glb_file_queue, queue_t * glb_dir_queue) { //We have a list of dirs //Loop through each of them while(1) { queue_element_t * item = remove_from_queue(loc_dir_queue); if(item == NULL) { return; } //Get the str from this item char * str = item->path_name; //Process this dir process_dir(str,glb_file_queue, glb_dir_queue); } }
void handle_string(char * str, char ** result, void * state){ struct Queue * queue = (struct Queue *) state; *result = NULL; if (queue == NULL) exit(1); char *command, *body; command = strtok_r(str, " ", &body); if (command != NULL && !strncmp(command, PUSH, PUSHLEN)){ add_to_queue(queue, body); } else if (str != NULL && !strncmp(str, POP, POPLEN)){ remove_from_queue(queue, result); } else { printf("don't know what we did\n"); } }
// Give up the CPU for one scheduling round. void yield(void) { //cprintf("Entered yield\n"); acquire(&ptable.lock); //DOC: yieldlock proc->state = RUNNABLE; // START HW4 // put process at end of queue acquire(&runqueue.lock); remove_from_queue( proc->pid, proc->priority ); enqueue( proc->pid,proc->priority ); // release(&runqueue.lock); // END HW4 sched(); release(&ptable.lock); }
//Given files just for this thread and global num found void process_files(queue_t * loc_file_queue, unsigned int * num_found, char * to_find) { unsigned int local_num_found = 0; //We have a list of files //Loop through each of them while(1) { queue_element_t * item = remove_from_queue(loc_file_queue); if(item == NULL) { //Done increment global with local (*num_found) +=local_num_found; return; } //Get the str from this item char * str = item->path_name; //Process this dir process_file(str, to_find, &local_num_found); } }
static void net_timer_runner(void *arg) { (void) arg; net_timer_event *e; bigtime_t now; t_current_set_name("Net Timer"); for(;;) { //sem_acquire_etc(net_q.wait_sem, 1, SEM_FLAG_TIMEOUT, NET_TIMER_INTERVAL, NULL); hal_sleep_msec(NET_TIMER_INTERVAL); now = system_time(); //printf("(^)"); retry: mutex_lock(&net_q.lock); // pull off the head of the list and run it, if it timed out if((e = peek_queue_head()) != NULL && e->sched_time <= now) { remove_from_queue(e); e->pending = false; mutex_unlock(&net_q.lock); e->func(e->args); // Since we ran an event, loop back and check the head of // the list again, because the list may have changed while // inside the callback. goto retry; } else { mutex_unlock(&net_q.lock); } } }
/* Go through the pending queue for the indicated semaphore * looking for tasks that can be completed. Keep cycling through * the queue until a pass is made in which no process is woken up. */ static void update_queue (struct semid_ds * sma) { int wokeup, error; struct sem_queue * q; do { wokeup = 0; for (q = sma->sem_pending; q; q = q->next) { error = try_semop(sma, q->sops, q->nsops); /* Does q->sleeper still need to sleep? */ if (error > 0) continue; /* Perform the operations the sleeper was waiting for */ if (!error) error = do_semop(sma, q->sops, q->nsops, q->undo, q->pid); q->status = error; /* Remove it from the queue */ remove_from_queue(sma,q); /* Wake it up */ wake_up_interruptible(&q->sleeper); /* doesn't sleep! */ wokeup++; } } while (wokeup); }
static void *start_smoothing( void *ptr ) { obe_t *h = ptr; int num_muxed_data = 0, buffer_complete = 0; int64_t start_clock = -1, start_pcr, end_pcr, temporal_vbv_size = 0, cur_pcr; obe_muxed_data_t **muxed_data = NULL, *start_data, *end_data; AVFifoBuffer *fifo_data = NULL, *fifo_pcr = NULL; uint8_t *output_buf; struct sched_param param = {0}; param.sched_priority = 99; pthread_setschedparam( pthread_self(), SCHED_FIFO, ¶m ); /* This thread buffers one VBV worth of frames */ fifo_data = av_fifo_alloc( TS_PACKETS_SIZE ); if( !fifo_data ) { fprintf( stderr, "[mux-smoothing] Could not allocate data fifo" ); return NULL; } fifo_pcr = av_fifo_alloc( 7 * sizeof(int64_t) ); if( !fifo_pcr ) { fprintf( stderr, "[mux-smoothing] Could not allocate pcr fifo" ); return NULL; } if( h->obe_system == OBE_SYSTEM_TYPE_GENERIC ) { for( int i = 0; i < h->num_encoders; i++ ) { if( h->encoders[i]->is_video ) { pthread_mutex_lock( &h->encoders[i]->queue.mutex ); while( !h->encoders[i]->is_ready ) pthread_cond_wait( &h->encoders[i]->queue.in_cv, &h->encoders[i]->queue.mutex ); x264_param_t *params = h->encoders[i]->encoder_params; temporal_vbv_size = av_rescale_q_rnd( (int64_t)params->rc.i_vbv_buffer_size * params->rc.f_vbv_buffer_init, (AVRational){1, params->rc.i_vbv_max_bitrate }, (AVRational){ 1, OBE_CLOCK }, AV_ROUND_UP ); pthread_mutex_unlock( &h->encoders[i]->queue.mutex ); break; } } } while( 1 ) { pthread_mutex_lock( &h->mux_smoothing_queue.mutex ); while( h->mux_smoothing_queue.size == num_muxed_data && !h->cancel_mux_smoothing_thread ) pthread_cond_wait( &h->mux_smoothing_queue.in_cv, &h->mux_smoothing_queue.mutex ); if( h->cancel_mux_smoothing_thread ) { pthread_mutex_unlock( &h->mux_smoothing_queue.mutex ); break; } num_muxed_data = h->mux_smoothing_queue.size; /* Refill the buffer after a drop */ pthread_mutex_lock( &h->drop_mutex ); if( h->mux_drop ) { syslog( LOG_INFO, "Mux smoothing buffer reset\n" ); h->mux_drop = 0; av_fifo_reset( fifo_data ); av_fifo_reset( fifo_pcr ); buffer_complete = 0; start_clock = -1; } pthread_mutex_unlock( &h->drop_mutex ); if( !buffer_complete ) { start_data = h->mux_smoothing_queue.queue[0]; end_data = h->mux_smoothing_queue.queue[num_muxed_data-1]; start_pcr = start_data->pcr_list[0]; end_pcr = end_data->pcr_list[(end_data->len / 188)-1]; if( end_pcr - start_pcr >= temporal_vbv_size ) { buffer_complete = 1; start_clock = -1; } else { pthread_mutex_unlock( &h->mux_smoothing_queue.mutex ); continue; } } //printf("\n mux smoothed frames %i \n", num_muxed_data ); muxed_data = malloc( num_muxed_data * sizeof(*muxed_data) ); if( !muxed_data ) { pthread_mutex_unlock( &h->output_queue.mutex ); syslog( LOG_ERR, "Malloc failed\n" ); return NULL; } memcpy( muxed_data, h->mux_smoothing_queue.queue, num_muxed_data * sizeof(*muxed_data) ); pthread_mutex_unlock( &h->mux_smoothing_queue.mutex ); for( int i = 0; i < num_muxed_data; i++ ) { if( av_fifo_realloc2( fifo_data, av_fifo_size( fifo_data ) + muxed_data[i]->len ) < 0 ) { syslog( LOG_ERR, "Malloc failed\n" ); return NULL; } av_fifo_generic_write( fifo_data, muxed_data[i]->data, muxed_data[i]->len, NULL ); if( av_fifo_realloc2( fifo_pcr, av_fifo_size( fifo_pcr ) + ((muxed_data[i]->len * sizeof(int64_t)) / 188) ) < 0 ) { syslog( LOG_ERR, "Malloc failed\n" ); return NULL; } av_fifo_generic_write( fifo_pcr, muxed_data[i]->pcr_list, (muxed_data[i]->len * sizeof(int64_t)) / 188, NULL ); remove_from_queue( &h->mux_smoothing_queue ); destroy_muxed_data( muxed_data[i] ); } free( muxed_data ); muxed_data = NULL; num_muxed_data = 0; while( av_fifo_size( fifo_data ) >= TS_PACKETS_SIZE ) { output_buf = malloc( TS_PACKETS_SIZE + 7 * sizeof(int64_t) ); if( !output_buf ) { syslog( LOG_ERR, "Malloc failed\n" ); return NULL; } av_fifo_generic_read( fifo_pcr, output_buf, 7 * sizeof(int64_t), NULL ); av_fifo_generic_read( fifo_data, &output_buf[7 * sizeof(int64_t)], TS_PACKETS_SIZE, NULL ); cur_pcr = AV_RN64( output_buf ); if( start_clock != -1 ) { sleep_input_clock( h, cur_pcr - start_pcr + start_clock ); } if( start_clock == -1 ) { start_clock = get_input_clock_in_mpeg_ticks( h ); start_pcr = cur_pcr; } if( add_to_queue( &h->output_queue, output_buf ) < 0 ) return NULL; output_buf = NULL; } } av_fifo_free( fifo_data ); av_fifo_free( fifo_pcr ); return NULL; }
static void *start_encoder( void *ptr ) { obe_aud_enc_params_t *enc_params = ptr; obe_t *h = enc_params->h; obe_encoder_t *encoder = enc_params->encoder; obe_output_stream_t *stream = enc_params->stream; obe_raw_frame_t *raw_frame; obe_coded_frame_t *coded_frame; void *audio_buf = NULL; int64_t cur_pts = -1, pts_increment; int i, frame_size, ret, got_pkt, num_frames = 0, total_size = 0, audio_buf_len; AVFifoBuffer *out_fifo = NULL; AVAudioResampleContext *avr = NULL; AVPacket pkt; AVCodecContext *codec = NULL; AVFrame *frame = NULL; AVDictionary *opts = NULL; char is_latm[2]; avcodec_register_all(); codec = avcodec_alloc_context3( NULL ); if( !codec ) { fprintf( stderr, "Malloc failed\n" ); goto finish; } for( i = 0; lavc_encoders[i].obe_name != -1; i++ ) { if( lavc_encoders[i].obe_name == stream->stream_format ) break; } if( lavc_encoders[i].obe_name == -1 ) { fprintf( stderr, "[lavc] Could not find encoder1\n" ); goto finish; } AVCodec *enc = avcodec_find_encoder( lavc_encoders[i].lavc_name ); if( !enc ) { fprintf( stderr, "[lavc] Could not find encoder2\n" ); goto finish; } if( enc->sample_fmts[0] == -1 ) { fprintf( stderr, "[lavc] No valid sample formats\n" ); goto finish; } codec->sample_rate = enc_params->sample_rate; codec->bit_rate = stream->bitrate * 1000; codec->sample_fmt = enc->sample_fmts[0]; codec->channels = av_get_channel_layout_nb_channels( stream->channel_layout ); codec->channel_layout = stream->channel_layout; codec->time_base.num = 1; codec->time_base.den = OBE_CLOCK; codec->profile = stream->aac_opts.aac_profile == AAC_HE_V2 ? FF_PROFILE_AAC_HE_V2 : stream->aac_opts.aac_profile == AAC_HE_V1 ? FF_PROFILE_AAC_HE : FF_PROFILE_AAC_LOW; snprintf( is_latm, sizeof(is_latm), "%i", stream->aac_opts.latm_output ); av_dict_set( &opts, "latm", is_latm, 0 ); av_dict_set( &opts, "header_period", "2", 0 ); if( avcodec_open2( codec, enc, &opts ) < 0 ) { fprintf( stderr, "[lavc] Could not open encoder\n" ); goto finish; } avr = avresample_alloc_context(); if( !avr ) { fprintf( stderr, "Malloc failed\n" ); goto finish; } av_opt_set_int( avr, "in_channel_layout", codec->channel_layout, 0 ); av_opt_set_int( avr, "in_sample_fmt", enc_params->input_sample_format, 0 ); av_opt_set_int( avr, "in_sample_rate", enc_params->sample_rate, 0 ); av_opt_set_int( avr, "out_channel_layout", codec->channel_layout, 0 ); av_opt_set_int( avr, "out_sample_fmt", codec->sample_fmt, 0 ); av_opt_set_int( avr, "dither_method", AV_RESAMPLE_DITHER_TRIANGULAR_NS, 0 ); if( avresample_open( avr ) < 0 ) { fprintf( stderr, "Could not open AVResample\n" ); goto finish; } /* The number of samples per E-AC3 frame is unknown until the encoder is ready */ if( stream->stream_format == AUDIO_E_AC_3 || stream->stream_format == AUDIO_AAC ) { pthread_mutex_lock( &encoder->queue.mutex ); encoder->is_ready = 1; encoder->num_samples = codec->frame_size; /* Broadcast because input and muxer can be stuck waiting for encoder */ pthread_cond_broadcast( &encoder->queue.in_cv ); pthread_mutex_unlock( &encoder->queue.mutex ); } frame_size = (double)codec->frame_size * 125 * stream->bitrate * enc_params->frames_per_pes / enc_params->sample_rate; /* NB: libfdk-aac already doubles the frame size appropriately */ pts_increment = (double)codec->frame_size * OBE_CLOCK * enc_params->frames_per_pes / enc_params->sample_rate; out_fifo = av_fifo_alloc( frame_size ); if( !out_fifo ) { fprintf( stderr, "Malloc failed\n" ); goto finish; } audio_buf_len = codec->frame_size * av_get_bytes_per_sample( codec->sample_fmt ) * codec->channels; audio_buf = av_malloc( audio_buf_len ); if( !audio_buf ) { fprintf( stderr, "Malloc failed\n" ); goto finish; } frame = avcodec_alloc_frame(); if( !frame ) { fprintf( stderr, "Could not allocate frame\n" ); goto finish; } while( 1 ) { /* TODO: detect bitrate or channel reconfig */ pthread_mutex_lock( &encoder->queue.mutex ); while( !encoder->queue.size && !encoder->cancel_thread ) pthread_cond_wait( &encoder->queue.in_cv, &encoder->queue.mutex ); if( encoder->cancel_thread ) { pthread_mutex_unlock( &encoder->queue.mutex ); goto finish; } raw_frame = encoder->queue.queue[0]; pthread_mutex_unlock( &encoder->queue.mutex ); if( cur_pts == -1 ) cur_pts = raw_frame->pts; if( avresample_convert( avr, NULL, 0, raw_frame->audio_frame.num_samples, raw_frame->audio_frame.audio_data, raw_frame->audio_frame.linesize, raw_frame->audio_frame.num_samples ) < 0 ) { syslog( LOG_ERR, "[lavc] Sample format conversion failed\n" ); break; } raw_frame->release_data( raw_frame ); raw_frame->release_frame( raw_frame ); remove_from_queue( &encoder->queue ); while( avresample_available( avr ) >= codec->frame_size ) { got_pkt = 0; avcodec_get_frame_defaults( frame ); frame->nb_samples = codec->frame_size; avresample_read( avr, &audio_buf, codec->frame_size ); if( avcodec_fill_audio_frame( frame, codec->channels, codec->sample_fmt, audio_buf, audio_buf_len, 0 ) < 0 ) { syslog( LOG_ERR, "[lavc] Could not fill audio frame\n" ); break; } av_init_packet( &pkt ); pkt.data = NULL; pkt.size = 0; ret = avcodec_encode_audio2( codec, &pkt, frame, &got_pkt ); if( ret < 0 ) { syslog( LOG_ERR, "[lavc] Audio encoding failed\n" ); goto finish; } if( !got_pkt ) continue; total_size += pkt.size; num_frames++; if( av_fifo_realloc2( out_fifo, av_fifo_size( out_fifo ) + pkt.size ) < 0 ) { syslog( LOG_ERR, "Malloc failed\n" ); break; } av_fifo_generic_write( out_fifo, pkt.data, pkt.size, NULL ); obe_free_packet( &pkt ); if( num_frames == enc_params->frames_per_pes ) { coded_frame = new_coded_frame( encoder->output_stream_id, total_size ); if( !coded_frame ) { syslog( LOG_ERR, "Malloc failed\n" ); goto finish; } av_fifo_generic_read( out_fifo, coded_frame->data, total_size, NULL ); coded_frame->pts = cur_pts; coded_frame->random_access = 1; /* Every frame output is a random access point */ add_to_queue( &h->mux_queue, coded_frame ); /* We need to generate PTS because frame sizes have changed */ cur_pts += pts_increment; total_size = num_frames = 0; } } } finish: if( frame ) avcodec_free_frame( &frame ); if( audio_buf ) av_free( audio_buf ); if( out_fifo ) av_fifo_free( out_fifo ); if( avr ) avresample_free( &avr ); if( codec ) { avcodec_close( codec ); av_free( codec ); } free( enc_params ); return NULL; }
int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) { int i, id, size, error; struct semid_ds *sma; struct sembuf sops[SEMOPM], *sop; struct sem_undo *un; int undos = 0, alter = 0; if (nsops < 1 || semid < 0) return -EINVAL; if (nsops > SEMOPM) return -E2BIG; if (!tsops) return -EFAULT; if ((i = verify_area (VERIFY_READ, tsops, nsops * sizeof(*tsops)))) return i; memcpy_fromfs (sops, tsops, nsops * sizeof(*tsops)); id = (unsigned int) semid % SEMMNI; if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID) return -EINVAL; if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) return -EIDRM; for (i = 0; i < nsops; i++) { sop = &sops[i]; if (sop->sem_num >= sma->sem_nsems) return -EFBIG; if (sop->sem_flg & SEM_UNDO) undos++; if (sop->sem_op) alter++; } if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) return -EACCES; error = try_semop(sma, sops, nsops); if (error < 0) return error; if (undos) { /* Make sure we have an undo structure * for this process and this semaphore set. */ for (un = current->semundo; un; un = un->proc_next) if (un->semid == semid) break; if (!un) { size = sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems; un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC); if (!un) return -ENOMEM; memset(un, 0, size); un->semadj = (short *) &un[1]; un->semid = semid; un->proc_next = current->semundo; current->semundo = un; un->id_next = sma->undo; sma->undo = un; } } else un = NULL; if (error == 0) { /* the operations go through immediately */ error = do_semop(sma, sops, nsops, un, current->pid); /* maybe some queued-up processes were waiting for this */ update_queue(sma); return error; } else { /* We need to sleep on this operation, so we put the current * task into the pending queue and go to sleep. */ struct sem_queue queue; queue.sma = sma; queue.sops = sops; queue.nsops = nsops; queue.undo = un; queue.pid = current->pid; queue.status = 0; insert_into_queue(sma,&queue); queue.sleeper = NULL; current->semsleeping = &queue; interruptible_sleep_on(&queue.sleeper); current->semsleeping = NULL; /* When we wake up, either the operation is finished, * or some kind of error happened. */ if (!queue.prev) { /* operation is finished, update_queue() removed us */ return queue.status; } else { remove_from_queue(sma,&queue); return -EINTR; } } }
int __pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock, const struct timespec *abstime) { pthread_descr self = NULL; pthread_readlock_info *existing; int out_of_mem, have_lock_already; pthread_extricate_if extr; if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) return EINVAL; have_lock_already = rwlock_have_already(&self, rwlock, &existing, &out_of_mem); if (self == NULL) self = thread_self (); /* Set up extrication interface */ extr.pu_object = rwlock; extr.pu_extricate_func = rwlock_rd_extricate_func; /* Register extrication interface */ __pthread_set_own_extricate_if (self, &extr); for (;;) { __pthread_lock (&rwlock->__rw_lock, self); if (rwlock_can_rdlock(rwlock, have_lock_already)) break; enqueue (&rwlock->__rw_read_waiting, self); __pthread_unlock (&rwlock->__rw_lock); /* This is not a cancellation point */ if (timedsuspend (self, abstime) == 0) { int was_on_queue; __pthread_lock (&rwlock->__rw_lock, self); was_on_queue = remove_from_queue (&rwlock->__rw_read_waiting, self); __pthread_unlock (&rwlock->__rw_lock); if (was_on_queue) { __pthread_set_own_extricate_if (self, 0); return ETIMEDOUT; } /* Eat the outstanding restart() from the signaller */ suspend (self); } } __pthread_set_own_extricate_if (self, 0); ++rwlock->__rw_readers; __pthread_unlock (&rwlock->__rw_lock); if (have_lock_already || out_of_mem) { if (existing != NULL) ++existing->pr_lock_count; else ++self->p_untracked_readlock_count; } return 0; }
asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) { int id, size, error = -EINVAL; struct semid_ds *sma; struct sembuf sops[SEMOPM], *sop; struct sem_undo *un; int undos = 0, decrease = 0, alter = 0; struct sem_queue queue; lock_kernel(); if (nsops < 1 || semid < 0) goto out; error = -E2BIG; if (nsops > SEMOPM) goto out; error = -EFAULT; if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) goto out; id = (unsigned int) semid % SEMMNI; error = -EINVAL; if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID) goto out; error = -EIDRM; if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) goto out; error = -EFBIG; for (sop = sops; sop < sops + nsops; sop++) { if (sop->sem_num >= sma->sem_nsems) goto out; if (sop->sem_flg & SEM_UNDO) undos++; if (sop->sem_op < 0) decrease = 1; if (sop->sem_op > 0) alter = 1; } alter |= decrease; error = -EACCES; if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) goto out; if (undos) { /* Make sure we have an undo structure * for this process and this semaphore set. */ for (un = current->semundo; un; un = un->proc_next) if (un->semid == semid) break; if (!un) { size = sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems; un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC); if (!un) { error = -ENOMEM; goto out; } memset(un, 0, size); un->semadj = (short *) &un[1]; un->semid = semid; un->proc_next = current->semundo; current->semundo = un; un->id_next = sma->undo; sma->undo = un; } } else un = NULL; error = try_atomic_semop (sma, sops, nsops, un, current->pid, 0); if (error <= 0) goto update; /* We need to sleep on this operation, so we put the current * task into the pending queue and go to sleep. */ queue.sma = sma; queue.sops = sops; queue.nsops = nsops; queue.undo = un; queue.pid = current->pid; queue.alter = decrease; current->semsleeping = &queue; if (alter) append_to_queue(sma ,&queue); else prepend_to_queue(sma ,&queue); for (;;) { queue.status = -EINTR; queue.sleeper = NULL; interruptible_sleep_on(&queue.sleeper); /* * If queue.status == 1 we where woken up and * have to retry else we simply return. * If an interrupt occurred we have to clean up the * queue * */ if (queue.status == 1) { error = try_atomic_semop (sma, sops, nsops, un, current->pid,0); if (error <= 0) break; } else { error = queue.status;; if (queue.prev) /* got Interrupt */ break; /* Everything done by update_queue */ current->semsleeping = NULL; goto out; } } current->semsleeping = NULL; remove_from_queue(sma,&queue); update: if (alter) update_queue (sma); out: unlock_kernel(); return error; }
// TODO(byan23): Set inuse[] to 0? // Exit the current process. Does not return. // An exited process remains in the zombie state // until its parent calls wait() to find out it exited. void exit(void) { //cprintf("exit pid: %d.\n", proc->pid); struct proc *p; int fd; if(proc == initproc) panic("init exiting"); // Close all open files. for(fd = 0; fd < NOFILE; fd++){ if(proc->ofile[fd]){ fileclose(proc->ofile[fd]); proc->ofile[fd] = 0; } } iput(proc->cwd); proc->cwd = 0; acquire(&ptable.lock); // Parent might be sleeping in wait(). wakeup1(proc->parent); // Pass abandoned children to init. for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ if(p->parent == proc){ p->parent = initproc; if(p->state == ZOMBIE) wakeup1(initproc); } } // Jump into the scheduler, never to return. proc->state = ZOMBIE; int slot_no; for (slot_no = 0; slot_no < NPROC; ++slot_no) { if (&ptable.proc[slot_no] == proc) break; } //cprintf("found at slot: %d\n", slot_no); int pri = proc_stat.priority[slot_no]; switch(pri) { case 0: remove_from_queue(&q0_head, &q0_tail, proc); break; case 1: remove_from_queue(&q1_head, &q1_tail, proc); break; case 2: remove_from_queue(&q2_head, &q2_tail, proc); break; case 3: remove_from_queue(&q3_head, &q3_tail, proc); break; default: cprintf("Wrong priority queue while exiting.\n"); } proc_stat.inuse[slot_no] = 0; sched(); panic("zombie exit"); }
int sem_timedwait(sem_t *sem, const struct timespec *abstime) { pthread_descr self = thread_self(); pthread_extricate_if extr; int already_canceled = 0; int spurious_wakeup_count; __pthread_lock(&sem->__sem_lock, self); if (sem->__sem_value > 0) { --sem->__sem_value; __pthread_unlock(&sem->__sem_lock); return 0; } if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) { /* The standard requires that if the function would block and the time value is illegal, the function returns with an error. */ __pthread_unlock(&sem->__sem_lock); __set_errno (EINVAL); return -1; } /* Set up extrication interface */ extr.pu_object = sem; extr.pu_extricate_func = new_sem_extricate_func; /* Register extrication interface */ THREAD_SETMEM(self, p_sem_avail, 0); __pthread_set_own_extricate_if(self, &extr); /* Enqueue only if not already cancelled. */ if (!(THREAD_GETMEM(self, p_canceled) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) enqueue(&sem->__sem_waiting, self); else already_canceled = 1; __pthread_unlock(&sem->__sem_lock); if (already_canceled) { __pthread_set_own_extricate_if(self, 0); __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); } spurious_wakeup_count = 0; while (1) { if (timedsuspend(self, abstime) == 0) { int was_on_queue; /* __pthread_lock will queue back any spurious restarts that may happen to it. */ __pthread_lock(&sem->__sem_lock, self); was_on_queue = remove_from_queue(&sem->__sem_waiting, self); __pthread_unlock(&sem->__sem_lock); if (was_on_queue) { __pthread_set_own_extricate_if(self, 0); __set_errno (ETIMEDOUT); return -1; } /* Eat the outstanding restart() from the signaller */ suspend(self); } if (THREAD_GETMEM(self, p_sem_avail) == 0 && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) { /* Count resumes that don't belong to us. */ spurious_wakeup_count++; continue; } break; } __pthread_set_own_extricate_if(self, 0); /* Terminate only if the wakeup came from cancellation. */ /* Otherwise ignore cancellation because we got the semaphore. */ if (THREAD_GETMEM(self, p_woken_by_cancel) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { THREAD_SETMEM(self, p_woken_by_cancel, 0); __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); } /* We got the semaphore */ return 0; }
asmlinkage long sys_semtimedop (int semid, struct sembuf *tsops, unsigned nsops, const struct timespec *timeout) { int error = -EINVAL; struct sem_array *sma; struct sembuf fast_sops[SEMOPM_FAST]; struct sembuf* sops = fast_sops, *sop; struct sem_undo *un; int undos = 0, decrease = 0, alter = 0; struct sem_queue queue; unsigned long jiffies_left = 0; if (nsops < 1 || semid < 0) return -EINVAL; if (nsops > sc_semopm) return -E2BIG; if(nsops > SEMOPM_FAST) { sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL); if(sops==NULL) return -ENOMEM; } if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) { error=-EFAULT; goto out_free; } if (timeout) { struct timespec _timeout; if (copy_from_user(&_timeout, timeout, sizeof(*timeout))) { error = -EFAULT; goto out_free; } if (_timeout.tv_sec < 0 || _timeout.tv_nsec < 0 || _timeout.tv_nsec >= 1000000000L) { error = -EINVAL; goto out_free; } jiffies_left = timespec_to_jiffies(&_timeout); } sma = sem_lock(semid); error=-EINVAL; if(sma==NULL) goto out_free; error = -EIDRM; if (sem_checkid(sma,semid)) goto out_unlock_free; error = -EFBIG; for (sop = sops; sop < sops + nsops; sop++) { if (sop->sem_num >= sma->sem_nsems) goto out_unlock_free; if (sop->sem_flg & SEM_UNDO) undos++; if (sop->sem_op < 0) decrease = 1; if (sop->sem_op > 0) alter = 1; } alter |= decrease; error = -EACCES; if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) goto out_unlock_free; if (undos) { /* Make sure we have an undo structure * for this process and this semaphore set. */ un=current->semundo; while(un != NULL) { if(un->semid==semid) break; if(un->semid==-1) un=freeundos(sma,un); else un=un->proc_next; } if (!un) { error = alloc_undo(sma,&un,semid,alter); if(error) goto out_free; } } else un = NULL; error = try_atomic_semop (sma, sops, nsops, un, current->tgid, 0); if (error <= 0) goto update; /* We need to sleep on this operation, so we put the current * task into the pending queue and go to sleep. */ queue.sma = sma; queue.sops = sops; queue.nsops = nsops; queue.undo = un; queue.pid = current->tgid; queue.alter = decrease; queue.id = semid; if (alter) append_to_queue(sma ,&queue); else prepend_to_queue(sma ,&queue); current->semsleeping = &queue; for (;;) { struct sem_array* tmp; queue.status = -EINTR; queue.sleeper = current; current->state = TASK_INTERRUPTIBLE; sem_unlock(semid); if (timeout) jiffies_left = schedule_timeout(jiffies_left); else schedule(); tmp = sem_lock(semid); if(tmp==NULL) { if(queue.prev != NULL) BUG(); current->semsleeping = NULL; error = -EIDRM; goto out_free; } /* * If queue.status == 1 we where woken up and * have to retry else we simply return. * If an interrupt occurred we have to clean up the * queue * */ if (queue.status == 1) { error = try_atomic_semop (sma, sops, nsops, un, current->tgid, 0); if (error <= 0) break; } else { error = queue.status; if (error == -EINTR && timeout && jiffies_left == 0) error = -EAGAIN; if (queue.prev) /* got Interrupt */ break; /* Everything done by update_queue */ current->semsleeping = NULL; goto out_unlock_free; } } current->semsleeping = NULL; remove_from_queue(sma,&queue); update: if (alter) update_queue (sma); out_unlock_free: sem_unlock(semid); out_free: if(sops != fast_sops) kfree(sops); return error; }
static void *start_smoothing( void *ptr ) { obe_t *h = ptr; int num_enc_smoothing_frames = 0, buffer_frames = 0; int64_t start_dts = -1, start_pts = -1, last_clock = -1; obe_coded_frame_t *coded_frame = NULL; struct sched_param param = {0}; param.sched_priority = 99; pthread_setschedparam( pthread_self(), SCHED_FIFO, ¶m ); /* FIXME: when we have soft pulldown this will need changing */ if( h->obe_system == OBE_SYSTEM_TYPE_GENERIC ) { for( int i = 0; i < h->num_encoders; i++ ) { if( h->encoders[i]->is_video ) { pthread_mutex_lock( &h->encoders[i]->queue.mutex ); while( !h->encoders[i]->is_ready ) pthread_cond_wait( &h->encoders[i]->queue.in_cv, &h->encoders[i]->queue.mutex ); x264_param_t *params = h->encoders[i]->encoder_params; buffer_frames = params->sc.i_buffer_size; pthread_mutex_unlock( &h->encoders[i]->queue.mutex ); break; } } } int64_t send_delta = 0; while( 1 ) { pthread_mutex_lock( &h->enc_smoothing_queue.mutex ); if( h->cancel_enc_smoothing_thread ) { pthread_mutex_unlock( &h->enc_smoothing_queue.mutex ); break; } while( h->enc_smoothing_queue.size == num_enc_smoothing_frames ) pthread_cond_wait( &h->enc_smoothing_queue.in_cv, &h->enc_smoothing_queue.mutex ); if( h->cancel_enc_smoothing_thread ) { pthread_mutex_unlock( &h->enc_smoothing_queue.mutex ); break; } num_enc_smoothing_frames = h->enc_smoothing_queue.size; if( !h->enc_smoothing_buffer_complete ) { if( num_enc_smoothing_frames >= buffer_frames ) { h->enc_smoothing_buffer_complete = 1; start_dts = -1; } else { pthread_mutex_unlock( &h->enc_smoothing_queue.mutex ); continue; } } // printf("\n smoothed frames %i \n", num_enc_smoothing_frames ); coded_frame = h->enc_smoothing_queue.queue[0]; pthread_mutex_unlock( &h->enc_smoothing_queue.mutex ); /* The terminology can be a cause for confusion: * pts refers to the pts from the input which is monotonic * dts refers to the dts out of the encoder which is monotonic */ pthread_mutex_lock( &h->obe_clock_mutex ); //printf("\n dts gap %"PRIi64" \n", coded_frame->real_dts - start_dts ); //printf("\n pts gap %"PRIi64" \n", h->obe_clock_last_pts - start_pts ); last_clock = h->obe_clock_last_pts; if( start_dts == -1 ) { start_dts = coded_frame->real_dts; /* Wait until the next clock tick */ while( last_clock == h->obe_clock_last_pts ) pthread_cond_wait( &h->obe_clock_cv, &h->obe_clock_mutex ); start_pts = h->obe_clock_last_pts; } else if( coded_frame->real_dts - start_dts > h->obe_clock_last_pts - start_pts ) { //printf("\n waiting \n"); while( last_clock == h->obe_clock_last_pts ) pthread_cond_wait( &h->obe_clock_cv, &h->obe_clock_mutex ); } /* otherwise, continue since the frame is late */ pthread_mutex_unlock( &h->obe_clock_mutex ); add_to_queue( &h->mux_queue, coded_frame ); //printf("\n send_delta %"PRIi64" \n", get_input_clock_in_mpeg_ticks( h ) - send_delta ); //send_delta = get_input_clock_in_mpeg_ticks( h ); remove_from_queue( &h->enc_smoothing_queue ); pthread_mutex_lock( &h->enc_smoothing_queue.mutex ); h->enc_smoothing_last_exit_time = get_input_clock_in_mpeg_ticks( h ); pthread_mutex_unlock( &h->enc_smoothing_queue.mutex ); num_enc_smoothing_frames = 0; } return NULL; }
/* * add semadj values to semaphores, free undo structures. * undo structures are not freed when semaphore arrays are destroyed * so some of them may be out of date. * IMPLEMENTATION NOTE: There is some confusion over whether the * set of adjustments that needs to be done should be done in an atomic * manner or not. That is, if we are attempting to decrement the semval * should we queue up and wait until we can do so legally? * The original implementation attempted to do this (queue and wait). * The current implementation does not do so. The POSIX standard * and SVID should be consulted to determine what behavior is mandated. */ void sem_exit (void) { struct sem_queue *q; struct sem_undo *u, *un = NULL, **up, **unp; struct sem_array *sma; int nsems, i; /* If the current process was sleeping for a semaphore, * remove it from the queue. */ if ((q = current->semsleeping)) { int semid = q->id; sma = sem_lock(semid); current->semsleeping = NULL; if (q->prev) { if(sma==NULL) BUG(); remove_from_queue(q->sma,q); } if(sma!=NULL) sem_unlock(semid); } for (up = ¤t->semundo; (u = *up); *up = u->proc_next, kfree(u)) { int semid = u->semid; if(semid == -1) continue; sma = sem_lock(semid); if (sma == NULL) continue; if (u->semid == -1) goto next_entry; if (sem_checkid(sma,u->semid)) goto next_entry; /* remove u from the sma->undo list */ for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { if (u == un) goto found; } printk ("sem_exit undo list error id=%d\n", u->semid); goto next_entry; found: *unp = un->id_next; /* perform adjustments registered in u */ nsems = sma->sem_nsems; for (i = 0; i < nsems; i++) { struct sem * sem = &sma->sem_base[i]; sem->semval += u->semadj[i]; if (sem->semval < 0) sem->semval = 0; /* shouldn't happen */ sem->sempid = current->tgid; } sma->sem_otime = CURRENT_TIME; /* maybe some queued-up processes were waiting for this */ update_queue(sma); next_entry: sem_unlock(semid); } current->semundo = NULL; }