/* 每个struct sock的时钟函数 */ void net_timer (unsigned long data) { struct sock *sk = (struct sock*)data; /* 相当于获取时钟的类型吧, */ int why = sk->timeout; /* timeout is overwritten by 'delete_timer' and 'reset_timer' */ /* 判断sock是否已被其他进程使用,或者当前是否正在执行网络的下半部分, * 如果当前正在执行网络的下半部分,则重新设置sock的timer,同时添加到 * 内核时钟当中,等待下次执行 */ if (sk->inuse || in_inet_bh()) { sk->timer.expires = 10; add_timer(&sk->timer); return; } /* 设置sock为用 */ sk->inuse = 1; DPRINTF ((DBG_TMR, "net_timer: found sk=%X why = %d\n", sk, why)); if (sk->wfront && before(sk->window_seq, sk->wfront->h.seq) && sk->send_head == NULL && sk->ack_backlog == 0 && sk->state != TCP_TIME_WAIT) reset_timer(sk, TIME_PROBE0, sk->rto); else if (sk->keepopen) reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); /* Always see if we need to send an ack. */ /* 看看还有没有收到的数据包没有应答 */ if (sk->ack_backlog) { /* sock发送确认数据包*/ sk->prot->read_wakeup (sk); if (! sk->dead) wake_up_interruptible (sk->sleep); } /* Now we need to figure out why the socket was on the timer. */ switch (why) { case TIME_DONE: if (! sk->dead || sk->state != TCP_CLOSE) { printk ("non dead socket in time_done\n"); release_sock (sk); break; } destroy_sock (sk); break; case TIME_DESTROY: /* We've waited for a while for all the memory associated with * the socket to be freed. We need to print an error message. */ /* 如果sock的发送缓冲区和接收缓冲区都为空,则直接在后面的语句当中释放 */ if(sk->wmem_alloc!=0 || sk->rmem_alloc!=0) { DPRINTF ((DBG_TMR, "possible memory leak. sk = %X\n", sk)); sk->wmem_alloc++; /* So it DOESNT go away */ destroy_sock (sk); sk->wmem_alloc--; /* Might now have hit 0 - fall through and do it again if so */ sk->inuse = 0; /* This will be ok, the destroy won't totally work */ } if(sk->wmem_alloc==0 && sk->rmem_alloc==0) destroy_sock(sk); /* Socket gone, DONT update sk->inuse! */ break; case TIME_CLOSE: /* We've waited long enough, close the socket. */ sk->state = TCP_CLOSE; delete_timer (sk); /* Kill the ARP entry in case the hardware has changed. */ arp_destroy_maybe (sk->daddr); if (!sk->dead) wake_up_interruptible (sk->sleep); sk->shutdown = SHUTDOWN_MASK; reset_timer (sk, TIME_DESTROY, TCP_DONE_TIME); release_sock (sk); break; case TIME_PROBE0: /* 窗口探测定时器,也被称为坚持定时器 */ tcp_send_probe0(sk); release_sock (sk); break; case TIME_WRITE: /* 超时重传定时器 */ /* try to retransmit. */ /* It could be we got here because we needed to send an ack. * So we need to check for that. */ if (sk->send_head) { if (jiffies < (sk->send_head->when + sk->rto)) { reset_timer (sk, TIME_WRITE, (sk->send_head->when + sk->rto - jiffies)); release_sock (sk); break; } /* printk("timer: seq %d retrans %d out %d cong %d\n", sk->send_head->h.seq, sk->retransmits, sk->packets_out, sk->cong_window); */ DPRINTF ((DBG_TMR, "retransmitting.\n")); /* 调用tcp协议的超时重传函数 */ sk->prot->retransmit (sk, 0); if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) { DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 1\n")); arp_destroy_maybe (sk->daddr); ip_route_check (sk->daddr); } if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) { DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 2\n")); sk->err = ETIMEDOUT; if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_LAST_ACK) { sk->state = TCP_TIME_WAIT; reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); } else { sk->prot->close (sk, 1); break; } } } release_sock (sk); break; case TIME_KEEPOPEN: /* 保活定时器 */ /* Send something to keep the connection open. */ if (sk->prot->write_wakeup) sk->prot->write_wakeup (sk); sk->retransmits++; /* 因为是重发定时,所以会增加超时重发次数 */ if (sk->shutdown == SHUTDOWN_MASK) { sk->prot->close (sk, 1); sk->state = TCP_CLOSE; } if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) { DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n")); arp_destroy_maybe (sk->daddr); ip_route_check (sk->daddr); release_sock (sk); break; } if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) { DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n")); arp_destroy_maybe (sk->daddr); sk->err = ETIMEDOUT; if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) { sk->state = TCP_TIME_WAIT; if (!sk->dead) wake_up_interruptible (sk->sleep); release_sock (sk); } else { sk->prot->close (sk, 1); } break; } release_sock (sk); break; default: printk ("net timer expired - reason unknown, sk=%08X\n", (int)sk); release_sock (sk); break; } }
void recv_lprobe(task * tmp_packet) { aodv_neigh *tmp_neigh; l_probe *tmp_lprobe; u_int32_t res_sec, res_usec, sec, usec; tmp_lprobe = tmp_packet->data; tmp_neigh = find_aodv_neigh(tmp_packet->src_ip); if (tmp_neigh == NULL) { #ifdef DEBUG printk ("Error: Source %s of an incoming large probe-packet belongs to any neighbour\n", inet_ntoa(tmp_packet->src_ip)); #endif return; } //Update neighbor timelife delete_timer(tmp_neigh->ip, tmp_neigh->ip, NO_TOS, TASK_NEIGHBOR); insert_timer_simple(TASK_NEIGHBOR, HELLO_INTERVAL * (1 + ALLOWED_HELLO_LOSS) + 100, tmp_neigh->ip); update_timer_queue(); tmp_neigh->lifetime = HELLO_INTERVAL * (1 + ALLOWED_HELLO_LOSS) + 20 + getcurrtime(); if (tmp_lprobe->n_probe != tmp_neigh->ett.last_count) //if not equal, the don't belong to the same pair. { #ifdef DEBUG printk("Error: Invalid pair of probe-packets from %s\n",inet_ntoa(tmp_packet->src_ip) ); #endif return; } //NEW ETT-PAIR received - Timer is reloaded delete_timer(tmp_neigh->ip, tmp_neigh->ip, NO_TOS, TASK_ETT_CLEANUP); insert_timer_simple(TASK_ETT_CLEANUP, ETT_INTERVAL * (1 + ALLOWED_ETT_LOSS) + 100, tmp_neigh->ip); update_timer_queue(); sec = tmp_lprobe->sec; usec = tmp_lprobe->usec; res_sec = sec - tmp_neigh->ett.sec; if (res_sec == 0) //large packet still received on same the second-value to the small one, only usec was incremented res_usec = usec - tmp_neigh->ett.usec; else if (res_sec == 1) //large packet received in a new second-value res_usec=1000000 + usec - tmp_neigh->ett.sec; else { #ifdef DEBUG printk ("Too high delay between the probe-packets, difference in seconds of %d\n", res_sec); #endif res_usec = DEFAULT_ETT_METRIC; } tmp_neigh->ett.meas_delay = res_usec; tmp_neigh->recv_rate = ntohs(tmp_lprobe->my_rate); if (g_fixed_rate == 0) { delay_vector_add(tmp_neigh, ntohl(tmp_lprobe->last_meas_delay)); #ifdef DEBUG printk("Received Delay to %s: %d Usecs\n",inet_ntoa(tmp_neigh->ip) ,ntohl(tmp_lprobe->last_meas_delay)); #endif compute_estimation(tmp_neigh); } if (tmp_neigh->recv_rate == 0 || tmp_neigh->send_rate == 0) //Estimation is still undone! Fast_interval! tmp_neigh->ett.interval = ETT_FAST_INTERVAL; else tmp_neigh->ett.interval = ETT_INTERVAL; return; }
void net_timer (unsigned long data) { struct sock *sk = (struct sock*)data; int why = sk->timeout; /* * only process if socket is not in use */ if (sk->users) { sk->timer.expires = jiffies+HZ; add_timer(&sk->timer); sti(); return; } /* Always see if we need to send an ack. */ if (sk->ack_backlog && !sk->zapped) { sk->prot->read_wakeup (sk); if (! sk->dead) sk->data_ready(sk,0); } /* Now we need to figure out why the socket was on the timer. */ switch (why) { case TIME_DONE: /* If the socket hasn't been closed off, re-try a bit later */ if (!sk->dead) { reset_timer(sk, TIME_DONE, TCP_DONE_TIME); break; } if (sk->state != TCP_CLOSE) { printk ("non CLOSE socket in time_done\n"); break; } destroy_sock (sk); break; case TIME_DESTROY: /* * We've waited for a while for all the memory associated with * the socket to be freed. */ destroy_sock(sk); break; case TIME_CLOSE: /* We've waited long enough, close the socket. */ sk->state = TCP_CLOSE; delete_timer (sk); if (!sk->dead) sk->state_change(sk); sk->shutdown = SHUTDOWN_MASK; reset_timer (sk, TIME_DONE, TCP_DONE_TIME); break; default: printk ("net_timer: timer expired - reason %d is unknown\n", why); break; } }
/*========================================== * Removes a instance, all its maps and npcs. *------------------------------------------*/ int instance_destroy(short instance_id) { struct instance_data *im; struct party_data *p; int i, type = 0, count = 0; unsigned int now = (unsigned int)time(NULL); if(instance_id <= 0 || instance_id > MAX_INSTANCE_DATA) return 1; im = &instance_data[instance_id]; if(im->state == INSTANCE_FREE) return 1; if(im->state == INSTANCE_IDLE) { for(i = 0; i < instance_wait.count; i++) { if(instance_wait.id[i] == instance_id) { instance_wait.count--; memmove(&instance_wait.id[i],&instance_wait.id[i+1],sizeof(instance_wait.id[0])*(instance_wait.count-i)); memset(&instance_wait.id[instance_wait.count], 0, sizeof(instance_wait.id[0])); for(i = 0; i < instance_wait.count; i++) if(instance_data[instance_wait.id[i]].state == INSTANCE_IDLE) if((p = party_search(instance_data[instance_wait.id[i]].party_id)) != NULL) clif_instance_changewait( party_getavailablesd( p ), i+1, 1); if(instance_wait.count) instance_wait.timer = add_timer(gettick()+INSTANCE_INTERVAL, instance_subscription_timer, 0, 0); else instance_wait.timer = -1; type = 0; break; } } } else { if(im->keep_limit && im->keep_limit <= now) type = 1; else if(im->idle_limit && im->idle_limit <= now) type = 2; else type = 3; for(i = 0; i < MAX_MAP_PER_INSTANCE; i++) count += map_delinstancemap(im->map[i].m); } if(im->keep_timer != -1) { delete_timer(im->keep_timer, instance_delete_timer); im->keep_timer = -1; } if(im->idle_timer != -1) { delete_timer(im->idle_timer, instance_delete_timer); im->idle_timer = -1; } if((p = party_search(im->party_id))) { p->instance_id = 0; if(type) clif_instance_changestatus( party_getavailablesd( p ), type, 0, 1 ); else clif_instance_changewait( party_getavailablesd( p ), 0xffff, 1 ); } if( im->vars ) { db_destroy(im->vars); im->vars = NULL; } ShowInfo("[Instance] Destroyed %d.\n", instance_id); memset(&instance_data[instance_id], 0, sizeof(instance_data[instance_id])); return 0; }
static void post_event_once(struct timerobj *tmobj) { struct psos_tm *tm = container_of(tmobj, struct psos_tm, tmobj); ev_send(tm->tid, tm->events); delete_timer(tm); }
long sys_timer_control(long id,long cmd,long arg1,long arg2,long arg3) { long r=-EINVAL; task_t *caller=current_task(); posix_stuff_t *stuff=caller->posix_stuff; posix_timer_t *ptimer; itimerspec_t tspec,kspec; ktimer_t *ktimer; #ifdef CONFIG_DEBUG_TIMERS kprintf_fault("sys_timer_control(<BEGIN>) [%d:%d]: Tick=%d,(cmd=%d,id=%d)\n", current_task()->pid,current_task()->tid, system_ticks,cmd,id); #endif switch( cmd ) { case __POSIX_TIMER_SETTIME: /* Arguments are the same as for POSIX 'timer_settime()': * arg1: int flags, arg2: struct itimerspec *value * arg3: struct itimerspec *ovalue */ if( !arg2 || copy_from_user(&tspec,(void *)arg2,sizeof(tspec)) ) { r=-EFAULT; } else { bool valid_timeval=timeval_is_valid(&tspec.it_value) && timeval_is_valid(&tspec.it_interval); ulong_t tx=time_to_ticks(&tspec.it_value); ulong_t itx=time_to_ticks(&tspec.it_interval); /* We need to hold the lock during the whole process, so lookup * target timer explicitely. */ LOCK_POSIX_STUFF_W(stuff); ptimer=(posix_timer_t*)__posix_locate_object(stuff,id,POSIX_OBJ_TIMER); if( !ptimer ) { break; } ktimer=&ptimer->ktimer; if( !(tspec.it_value.tv_sec | tspec.it_value.tv_nsec) ) { if( ktimer->time_x && posix_timer_active(ptimer) ) { /* Disarm active timer */ #ifdef CONFIG_DEBUG_TIMERS kprintf_fault("sys_timer_control() [%d:%d]: Tick=%d, deactivating timer %p:(P=%d) to %d\n", current_task()->pid,current_task()->tid, system_ticks,ktimer,ptimer->interval,tx); #endif deactivate_posix_timer(ptimer); delete_timer(ktimer); } r=0; } else if( valid_timeval ) { if( !(arg1 & TIMER_ABSTIME) ) { tx+=system_ticks; } ptimer->interval=itx; activate_posix_timer(ptimer); if( ktimer->time_x ) { /* New time for active timer. */ #ifdef CONFIG_DEBUG_TIMERS kprintf_fault("sys_timer_control() [%d:%d] <RE-ARM> Tick=%d, timer=%p:(Tv=%d/%d,Pv=%d/%d,ABS=%d) to %d\n", current_task()->pid,current_task()->tid, system_ticks,ktimer, tspec.it_value.tv_sec,tspec.it_value.tv_nsec, tspec.it_interval.tv_sec,tspec.it_interval.tv_nsec, (arg1 & TIMER_ABSTIME) != 0, tx); #endif r=modify_timer(ktimer,tx); } else { TIMER_RESET_TIME(ktimer,tx); #ifdef CONFIG_DEBUG_TIMERS kprintf_fault("sys_timer_control() <ARM> [%d:%d] Tick=%d, timer=%p:(Tv=%d/%d,Pv=%d/%d,ABS=%d) to %d\n", current_task()->pid,current_task()->tid, system_ticks,ktimer, tspec.it_value.tv_sec,tspec.it_value.tv_nsec, tspec.it_interval.tv_sec,tspec.it_interval.tv_nsec, (arg1 & TIMER_ABSTIME) != 0, tx); #endif r=add_timer(ktimer); } } UNLOCK_POSIX_STUFF_W(stuff); if( !r && arg3 ) { __get_timer_status(ptimer,&kspec); if( copy_to_user((itimerspec_t *)arg3,&kspec,sizeof(kspec)) ) { r=-EFAULT; /* TODO: [mt] Cleanup timer upon -EFAULT. */ } } } break; case __POSIX_TIMER_GETTIME: ptimer=posix_lookup_timer(stuff,id); if( !ptimer ) { break; } __get_timer_status(ptimer,&kspec); r=copy_to_user((itimerspec_t *)arg1,&kspec,sizeof(kspec)) ? -EFAULT : 0; break; case __POSIX_TIMER_GETOVERRUN: ptimer=posix_lookup_timer(stuff,id); if( !ptimer ) { break; } r=ptimer->overrun; break; default: r=-EINVAL; break; } if( ptimer ) { release_posix_timer(ptimer); } #ifdef CONFIG_DEBUG_TIMERS kprintf_fault("sys_timer_control(<END>) [%d:%d]: Tick=%d, (cmd=%d,id=%d), result=%d\n", current_task()->pid,current_task()->tid, system_ticks,cmd,id,r); #endif return ERR(r); }
int main(int argc,char **argv) { LONG seconds; struct timerequest *tr; /* IO block for timer commands */ struct timeval oldtimeval; /* timevals to store times */ struct timeval mytimeval; struct timeval currentval; printf("\nTimer test\n"); /* sleep for two seconds */ currentval.tv_secs = 2; currentval.tv_micro = 0; time_delay( ¤tval, UNIT_VBLANK ); printf( "After 2 seconds delay\n" ); /* sleep for four seconds */ currentval.tv_secs = 4; currentval.tv_micro = 0; time_delay( ¤tval, UNIT_VBLANK ); printf( "After 4 seconds delay\n" ); /* sleep for 500,000 micro-seconds = 1/2 second */ currentval.tv_secs = 0; currentval.tv_micro = 500000; time_delay( ¤tval, UNIT_MICROHZ ); printf( "After 1/2 second delay\n" ); printf( "DOS Date command shows: " ); (void) Execute( "date", 0, 0 ); /* save what system thinks is the time....we'll advance it temporarily */ get_sys_time( &oldtimeval ); printf("Original system time is:\n"); show_time(oldtimeval.tv_secs ); printf("Setting a new system time\n"); seconds = 1000 * SECSPERDAY + oldtimeval.tv_secs; set_new_time( seconds ); /* (if user executes the AmigaDOS DATE command now, he will*/ /* see that the time has advanced something over 1000 days */ printf( "DOS Date command now shows: " ); (void) Execute( "date", 0, 0 ); get_sys_time( &mytimeval ); printf( "Current system time is:\n"); show_time(mytimeval.tv_secs); /* Added the microseconds part to show that time keeps */ /* increasing even though you ask many times in a row */ printf("Now do three TR_GETSYSTIMEs in a row (notice how the microseconds increase)\n\n"); get_sys_time( &mytimeval ); printf("First TR_GETSYSTIME \t%ld.%ld\n",mytimeval.tv_secs, mytimeval.tv_micro); get_sys_time( &mytimeval ); printf("Second TR_GETSYSTIME \t%ld.%ld\n",mytimeval.tv_secs, mytimeval.tv_micro); get_sys_time( &mytimeval ); printf("Third TR_GETSYSTIME \t%ld.%ld\n",mytimeval.tv_secs, mytimeval.tv_micro); printf( "\nResetting to former time\n" ); set_new_time( oldtimeval.tv_secs ); get_sys_time( &mytimeval ); printf( "Current system time is:\n"); show_time(mytimeval.tv_secs); /* just shows how to set up for using the timer functions, does not */ /* demonstrate the functions themselves. (TimerBase must have a */ /* legal value before AddTime, SubTime or CmpTime are performed. */ tr = create_timer( UNIT_MICROHZ ); if (tr) TimerBase = (struct Library *)tr->tr_node.io_Device; else printf("Could't create timer with UNIT_MICROHZ\n"); /* and how to clean up afterwards */ TimerBase = (struct Library *)(-1); delete_timer( tr ); return 0; }
void harmony_action_request_global(int task, int id, intptr data) { switch (task) { case HARMTASK_LOGIN_ACTION: chrif_harmony_request((uint8*)data, id); break; case HARMTASK_GET_FD: { TBL_PC *sd = BL_CAST(BL_PC, map_id2bl(id)); *(int32*)data = (sd ? sd->fd : 0); } break; case HARMTASK_SET_LOG_METHOD: log_method = id; break; case HARMTASK_INIT_GROUPS: if (chrif_isconnected()) harmony_register_groups(); else { // Register groups as soon as the char server is available again if (tid_group_register != INVALID_TIMER) delete_timer(tid_group_register, harmony_group_register_timer); tid_group_register = add_timer_interval(gettick()+1000, harmony_group_register_timer, 0, 0, 500); } break; case HARMTASK_RESOLVE_GROUP: #if HARMSW == HARMSW_RATHENA_GROUP *(int32*)data = pc_group_id2level(id); #else *(int32*)data = id; #endif break; case HARMTASK_PACKET: clif_send((const uint8*)data, id, NULL, ALL_CLIENT); break; case HARMTASK_GET_ADMINS: { #if HARMSW == HARMSW_RATHENA_GROUP // Iterate groups and register each group individually current_groupscan_minlevel = id; pc_group_iterate(harmony_iterate_groups_adminlevel); #else // int account_id; int level = id; if (SQL_SUCCESS != SqlStmt_BindParam(admin_stmt, 0, SQLDT_INT, (void*)&level, sizeof(level)) || SQL_SUCCESS != SqlStmt_Execute(admin_stmt)) { ShowError("Fetching GM accounts failed.\n"); Sql_ShowDebug(mmysql_handle); break; } SqlStmt_BindColumn(admin_stmt, 0, SQLDT_INT, &account_id, 0, NULL, NULL); while (SQL_SUCCESS == SqlStmt_NextRow(admin_stmt)) { harm_funcs->zone_register_admin(account_id, false); } #endif break; } case HARMTASK_IS_CHAR_CONNECTED: *(int*)data = chrif_isconnected(); break; default: ShowError("Harmony requested unknown action! (Global; ID=%d)\n", task); ShowError("This indicates that you are running an incompatible version.\n"); break; } }
int bg_team_clean(int bg_id, bool remove) { // Deletes BG Team from db int i; struct map_session_data *sd; struct battleground_data *bg = bg_team_search(bg_id); struct guild *g; if( bg == NULL ) return 0; for( i = 0; i < MAX_BG_MEMBERS; i++ ) { if( (sd = bg->members[i].sd) == NULL ) continue; bg_send_dot_remove(sd); sd->bg_id = 0; sd->state.bg_afk = 0; sd->bmaster_flag = NULL; bg_member_removeskulls(sd); // Remove Guild Skill Buffs status_change_end(&sd->bl,SC_GUILDAURA,INVALID_TIMER); status_change_end(&sd->bl,SC_BATTLEORDERS,INVALID_TIMER); status_change_end(&sd->bl,SC_REGENERATION,INVALID_TIMER); if( !battle_config.bg_eAmod_mode ) continue; // No need to touch Guild stuff if( sd->status.guild_id && (g = guild_search(sd->status.guild_id)) != NULL ) { clif_guild_belonginfo(sd,g); clif_guild_basicinfo(sd); clif_guild_allianceinfo(sd); clif_guild_memberlist(sd); clif_guild_skillinfo(sd); } else clif_bg_leave_single(sd, sd->status.name, "Leaving Battleground..."); clif_charnameupdate(sd); clif_guild_emblem_area(&sd->bl); } for( i = 0; i < MAX_GUILDSKILL; i++ ) { if( bg->skill_block_timer[i] == INVALID_TIMER ) continue; delete_timer(bg->skill_block_timer[i], bg_block_skill_end); } if( remove ) idb_remove(bg_team_db, bg_id); else { bg->count = 0; bg->leader_char_id = 0; bg->team_score = 0; bg->creation_tick = 0; memset(&bg->members, 0, sizeof(bg->members)); } return 1; }
void elemental_summon_stop(struct elemental_data *ed) { nullpo_retv(ed); if( ed->summon_timer != INVALID_TIMER ) delete_timer(ed->summon_timer, elemental_summon_end); ed->summon_timer = INVALID_TIMER; }
/* * You call this to register a timer callback. * * The arguments: * update: This should be 1 if we're updating the specified refnum * refnum_want: The refnum requested. * (1) User-supplied for /TIMER timers * (2) the empty string for system timers ("dont care") * interval: How long until the timer should fire; * (1) for repeating timers (events != 1), the timer will * fire with this interval. * (2) for "snap" timers, the first fire will be the next * time time() % interval == 0. * events: The number of times this event should fire. * (1) The value -1 means "repeat forever" * (2) Timers automatically delete after they fire the * requested number of times. * * Scenario 1: You want to run ircII commands (/TIMER timers) * | callback: NULL * | commands: some ircII commands to run when the timer goes off * | subargs: what to use to expand $0's, etc in the 'what' variable. * * Scenario 2: You want to call an internal function (system timers) * | callback: function to call when timer goes off * | commands: argument to pass to "callback" function. Should be some * | non-auto storage, perhaps a struct or a malloced char * * | array. The caller is responsible for disposing of this * | area when it is called, since the timer mechanism does not * | know anything of the nature of the argument. * | subargs: should be NULL, its ignored anyhow. * * domain: What the TIMER should bind to: * (a) SERVER_TIMER - 'domref' refers to a server refnum. * Each time this timer runs, set from_server to 'domref' * and set the current window to whatever 'domref's * current window is at that time. * (b) WINDOW_TIME - 'domref' refers to a window refnum. * Each time this timer runs, set current_window to * 'domref' and set the current server to whatever * 'domref's server is at that time. * (c) GENERAL_TIMER - 'domref' is ignored. * Do not save or restore from_server or current_window: * run in whatever the context is when it goes off. * domref: Either a server refnum, window refnum, or -1 (see 'domain') * cancelable: A "Cancelable" timer will not fire if its context cannot be * restored (ie, the server it is bound to is disconnected or * deleted; or the window it is bound to is deleted). A normal * (non-cancelable) timer will turn into a GENERAL_TIMER if its * context cannot be restored. * snap: A "snap" timer runs every time (time() % interval == 0). * This is useful for things that (eg) run at the top of every * minute (60), hour (3600), or day (86400) */ char *add_timer (int update, const char *refnum_want, double interval, long events, int (callback) (void *), void *commands, const char *subargs, TimerDomain domain, int domref, int cancelable, int snap) { Timer *ntimer, *otimer = NULL; char * refnum_got = NULL; Timeval right_now; char * retval; right_now = get_time(NULL); /* * We do this first, because if 'interval' is invalid, we don't * want to do the expensive clone/create/delete operation. * It is ineligant to check for this error here. */ if (update == 1 && interval == -1) /* Not changing the interval */ (void) 0; /* XXX sigh */ else if (interval < 0.01 && events == -1) { say("You can't infinitely repeat a timer that runs more " "than 100 times a second."); return NULL; } /* * If we say we're updating; but the timer does not exist, * then we're not updating. ;-) */ if (update) { if (!(otimer = get_timer(refnum_want))) update = 0; /* Ok so we're not updating! */ } /* * Arrange for an appropriate Timer to be in 'ntimer'. */ if (update) { unlink_timer(otimer); ntimer = clone_timer(otimer); delete_timer(otimer); } else { if (create_timer_ref(refnum_want, &refnum_got) == -1) { say("TIMER: Refnum '%s' already exists", refnum_want); return NULL; } ntimer = new_timer(); ntimer->ref = refnum_got; } /* Update the interval */ if (update == 1 && interval == -1) (void) 0; /* XXX sigh - not updating interval */ else { ntimer->interval = double_to_timeval(interval); if (snap) { double x = time_to_next_interval(interval); ntimer->time = time_add(right_now, double_to_timeval(x)); } else ntimer->time = time_add(right_now, ntimer->interval); } /* Update the repeat events */ if (update == 1 && events == -2) (void) 0; /* XXX sigh - not updating events */ else ntimer->events = events; /* Update the callback */ if (callback) { /* Delete the previous timer, if necessary */ if (ntimer->command) new_free(&ntimer->command); if (ntimer->subargs) new_free(&ntimer->subargs); ntimer->callback = callback; /* Unfortunately, command is "sometimes const". */ ntimer->callback_data = commands; ntimer->subargs = NULL; } else { ntimer->callback = NULL; malloc_strcpy(&ntimer->command, (const char *)commands); malloc_strcpy(&ntimer->subargs, subargs); } /* Update the domain refnum */ ntimer->domain = domain; if (update == 1 && domref == -1) (void) 0; /* XXX sigh - not updating domref */ else ntimer->domref = domref; /* Update the cancelable */ if (update == 1 && cancelable == -1) (void) 0; /* XXX sigh - not updating cancelable */ else ntimer->cancelable = cancelable; /* Schedule up the new/updated timer! */ schedule_timer(ntimer); retval = ntimer->ref; return retval; /* Eliminates a specious warning from gcc */ }
/* * ExecuteTimers: checks to see if any currently pending timers have * gone off, and if so, execute them, delete them, etc, setting the * current_exec_timer, so that we can't remove the timer while its * still executing. * * changed the behavior: timers will not hook while we are waiting. */ void ExecuteTimers (void) { Timeval right_now; Timer * current, *next; int old_from_server = from_server; get_time(&right_now); while (PendingTimers && time_diff(right_now, PendingTimers->time) < 0) { int old_refnum; old_refnum = current_window->refnum; current = PendingTimers; unlink_timer(current); /* Reschedule the timer if necessary */ if (current->events < 0 || (current->events != 1)) { next = clone_timer(current); if (next->events != -1) next->events--; next->time = time_add(next->time, next->interval); schedule_timer(next); } if (current->domain == SERVER_TIMER) { if (!is_server_valid(current->domref)) { if (current->cancelable) goto advance; /* Otherwise, pretend you were a "GENERAL" type */ } else { from_server = current->domref; make_window_current_by_refnum( get_winref_by_servref(from_server)); } } else if (current->domain == WINDOW_TIMER) { if (!get_window_by_refnum(current->domref)) { if (current->cancelable) goto advance; /* Otherwise, pretend you were a "GENERAL" type */ } else { make_window_current_by_refnum(current->domref); from_server = current_window->server; } } else { /* General timers focus on the current window. */ if (current_window) { if (current_window->server != from_server) from_server = current_window->server; } else { if (from_server != NOSERV) make_window_current_by_refnum( get_winref_by_servref(from_server)); } } /* * If a callback function was registered, then * we use it. If no callback function was registered, * then we call the lambda function. */ get_time(&right_now); now = right_now; if (current->callback) (*current->callback)(current->callback_data); else call_lambda_command("TIMER", current->command, current->subargs); from_server = old_from_server; make_window_current_by_refnum(old_refnum); advance: delete_timer(current); } }
/* * You call this to register a timer callback. * * The arguments: * update: This should be 1 if we're updating the specified refnum * refnum_want: The refnum requested. This should only be sepcified * by the user, functions wanting callbacks should specify * the empty string, which means "dont care". * The rest of the arguments are dependant upon the value of "callback" * -- if "callback" is NULL then: * callback: NULL * what: some ircII commands to run when the timer goes off * subargs: what to use to expand $0's, etc in the 'what' variable. * * -- if "callback" is non-NULL then: * callback: function to call when timer goes off * what: argument to pass to "callback" function. Should be some * non-auto storage, perhaps a struct or a malloced char * * array. The caller is responsible for disposing of this * area when it is called, since the timer mechanism does not * know anything of the nature of the argument. * subargs: should be NULL, its ignored anyhow. */ char *add_timer (int update, const char *refnum_want, double interval, long events, int (callback) (void *), void *commands, const char *subargs, int winref) { Timer *ntimer, *otimer = NULL; char refnum_got[REFNUM_MAX + 1]; Timeval right_now; char * retval; /* XXX Eh, maybe it's a hack to check this here. */ if (interval < 0.01 && events == -1) { say("You can't infinitely repeat a timer that runs more " "than 100 times a second."); return NULL; } right_now = get_time(NULL); if (update) { if (!(otimer = get_timer(refnum_want))) update = 0; /* Ok so we're not updating! */ } if (update) { unlink_timer(otimer); ntimer = clone_timer(otimer); delete_timer(otimer); if (interval != -1) { ntimer->interval = double_to_timeval(interval); ntimer->time = time_add(right_now, ntimer->interval); } if (events != -2) ntimer->events = events; if (callback) { /* Delete the previous timer, if necessary */ if (ntimer->command) new_free(&ntimer->command); if (ntimer->subargs) new_free(&ntimer->subargs); ntimer->callback = callback; /* Unfortunately, command is "sometimes const". */ ntimer->callback_data = commands; ntimer->subargs = NULL; } else { if (ntimer->callback) ntimer->callback = NULL; malloc_strcpy(&ntimer->command, (const char *)commands); malloc_strcpy(&ntimer->subargs, subargs); } if (winref != -1) ntimer->window = winref; } else { if (create_timer_ref(refnum_want, refnum_got) == -1) { say("TIMER: Refnum '%s' already exists", refnum_want); return NULL; } ntimer = new_timer(); strlcpy(ntimer->ref, refnum_got, sizeof ntimer->ref); ntimer->interval = double_to_timeval(interval); ntimer->time = time_add(right_now, ntimer->interval); ntimer->events = events; ntimer->callback = callback; /* Unfortunately, command is "sometimes const". */ if (callback) ntimer->callback_data = commands; else malloc_strcpy(&ntimer->command, (const char *)commands); malloc_strcpy(&ntimer->subargs, subargs); ntimer->window = winref; ntimer->server = from_server; } schedule_timer(ntimer); retval = ntimer->ref; return retval; /* Eliminates a specious warning from gcc */ }
// Give a timer to the data store. At this point the data store takes ownership // of the timer and the caller should not reference it again (as the timer store // may delete it at any time). void TimerStore::add_timer(Timer* t) { // First check if this timer already exists. auto map_it = _timer_lookup_table.find(t->id); if (map_it != _timer_lookup_table.end()) { Timer* existing = map_it->second; // Compare timers for precedence, start-time then sequence-number. if ((t->start_time < existing->start_time) || ((t->start_time == existing->start_time) && (t->sequence_number < existing->sequence_number))) { // Existing timer is more recent delete t; return; } else { // Existing timer is older if (t->is_tombstone()) { // Learn the interval so that this tombstone lasts long enough to catch // errors. t->interval = existing->interval; t->repeat_for = existing->interval; } delete_timer(t->id); } } // Work out where to store the timer (overdue bucket, short wheel, long wheel, // or heap). // // Note that these if tests MUST use less than. For example if _tick_time is // 20,330 a 1s timer will pop at 21,330. When in the short wheel the timer // will live in bucket 33. But this is the bucket that is about to pop, so the // timer must actually go in to the long wheel. The same logic applies for // the 1s buckets (where timers due to pop in >=1hr need to go into the heap). uint64_t next_pop_time = t->next_pop_time(); Bucket* bucket; if (next_pop_time < _tick_timestamp) { // The timer should have already popped so put it in the overdue timers, // and warn the user. // // We can't just put the timer in the next bucket to pop. We need to know // what bucket to look in when deleting timers, and this is derived from // the pop time. So if we put the timer in the wrong bucket we can't find // it to delete it. LOG_WARNING("Modifying timer after pop time (current time is %lu). " "Window condition detected.\n" TIMER_LOG_FMT, _tick_timestamp, TIMER_LOG_PARAMS(t)); _overdue_timers.insert(t); } else if (to_short_wheel_resolution(next_pop_time) < to_short_wheel_resolution(_tick_timestamp + SHORT_WHEEL_PERIOD_MS)) { bucket = short_wheel_bucket(next_pop_time); bucket->insert(t); } else if (to_long_wheel_resolution(next_pop_time) < to_long_wheel_resolution(_tick_timestamp + LONG_WHEEL_PERIOD_MS)) { bucket = long_wheel_bucket(next_pop_time); bucket->insert(t); } else { // Timer is too far in the future to be handled by the wheels, put it in // the extra heap. LOG_WARNING("Adding timer to extra heap, consider re-building with a larger " "LONG_WHEEL_NUM_BUCKETS constant"); _extra_heap.push_back(t); std::push_heap(_extra_heap.begin(), _extra_heap.end()); } // Finally, add the timer to the lookup table. _timer_lookup_table.insert(std::pair<TimerID, Timer*>(t->id, t)); }
void destroy_sock(struct sock *sk) { struct sk_buff *skb; sk->inuse = 1; /* just to be safe. */ /* In case it's sleeping somewhere. */ if (!sk->dead) sk->write_space(sk); remove_sock(sk); /* Now we can no longer get new packets. */ delete_timer(sk); /* Nor send them */ del_timer(&sk->retransmit_timer); while ((skb = tcp_dequeue_partial(sk)) != NULL) { IS_SKB(skb); kfree_skb(skb, FREE_WRITE); } /* Cleanup up the write buffer. */ while((skb = skb_dequeue(&sk->write_queue)) != NULL) { IS_SKB(skb); kfree_skb(skb, FREE_WRITE); } /* * Don't discard received data until the user side kills its * half of the socket. */ if (sk->dead) { while((skb=skb_dequeue(&sk->receive_queue))!=NULL) { /* * This will take care of closing sockets that were * listening and didn't accept everything. */ if (skb->sk != NULL && skb->sk != sk) { IS_SKB(skb); skb->sk->dead = 1; skb->sk->prot->close(skb->sk, 0); } IS_SKB(skb); kfree_skb(skb, FREE_READ); } } /* Now we need to clean up the send head. */ cli(); for(skb = sk->send_head; skb != NULL; ) { struct sk_buff *skb2; /* * We need to remove skb from the transmit queue, * or maybe the arp queue. */ if (skb->next && skb->prev) { /* printk("destroy_sock: unlinked skb\n");*/ IS_SKB(skb); skb_unlink(skb); } skb->dev = NULL; skb2 = skb->link3; kfree_skb(skb, FREE_WRITE); skb = skb2; } sk->send_head = NULL; sti(); /* And now the backlog. */ while((skb=skb_dequeue(&sk->back_log))!=NULL) { /* this should never happen. */ /* printk("cleaning back_log\n");*/ kfree_skb(skb, FREE_READ); } /* Now if it has a half accepted/ closed socket. */ if (sk->pair) { sk->pair->dead = 1; sk->pair->prot->close(sk->pair, 0); sk->pair = NULL; } /* * Now if everything is gone we can free the socket * structure, otherwise we need to keep it around until * everything is gone. */ if (sk->dead && sk->rmem_alloc == 0 && sk->wmem_alloc == 0) { kfree_s((void *)sk,sizeof(*sk)); } else { /* this should never happen. */ /* actually it can if an ack has just been sent. */ sk->destroy = 1; sk->ack_backlog = 0; sk->inuse = 0; reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME); } }