? server-0.ps ? ospfd/.nfs000ec4760000fe94 ? ospfd/DEADJOE Index: lib/ChangeLog =================================================================== RCS file: /var/cvsroot/quagga/lib/ChangeLog,v retrieving revision 1.8 diff -u -r1.8 ChangeLog --- lib/ChangeLog 21 Apr 2004 11:00:43 -0000 1.8 +++ lib/ChangeLog 30 Apr 2004 13:36:43 -0000 @@ -1,3 +1,31 @@ +2004-04-30 Paul Jakma + + * command.c: (config_write_host) Write out thread stride if not + default. (cmd_init) install thread_ready_stride_cmd's + thread.h: Add DEFAULT_STRIDE define, a bound of number of threads + to make ready in any given cycle of thread_fetch. Add stride field + to thread_master. Add THREAD_MAX_LOOP macro for bounded list loops. + Add externs for thread commands for command.c::cmd_init. + thread.c: (thread_ready_stride_cmd) Command to change thread + stride from default, and similar negate command. + (thread_master_create) set default stride + (thread_add_ready) new helper function + (thread_process_fd) renamed to thread_ready_fd + (thread_ready_fd) Use thread_add_ready, and use stride value + to limit the number of threads to add to ready list + (thread_fetch) Queue all threads via the ready list, using + stride to bound number of threads of a given type to add to ready + list in a given iteration. give writes higher priority than reads. + vty.h: record struct thread_master in struct vty. Needed for + thread_stride commands to find/set stride. + vty.c: Move static of thread_master to top - cant get rid of it + because of the pass-the-parcel way by which struct vty's are + maintained. + (vty_create) record thread_master in vty.c + (vty_event) use vty->master instead of the static. + global: Some indentation cleanups in and around functions affected + by changes. + 2004-04-21 Boris Kovalenko * daemon.c: (daemon) fix check for error return from setsid Index: lib/command.c =================================================================== RCS file: /var/cvsroot/quagga/lib/command.c,v retrieving revision 1.14 diff -u -r1.14 command.c --- lib/command.c 16 Mar 2004 14:38:36 -0000 1.14 +++ lib/command.c 30 Apr 2004 13:36:47 -0000 @@ -567,6 +567,10 @@ if (! host.motd) vty_out (vty, "no banner motd%s", VTY_NEWLINE); + if (vty->master) + if (vty->master->stride != QUAGGA_THREAD_DEFAULT_STRIDE) + vty_out (vty, "thread ready-stride %d%s", + vty->master->stride, VTY_NEWLINE); return 1; } @@ -3332,6 +3336,8 @@ install_element (CONFIG_NODE, &no_banner_motd_cmd); install_element (CONFIG_NODE, &service_terminal_length_cmd); install_element (CONFIG_NODE, &no_service_terminal_length_cmd); + install_element (CONFIG_NODE, &thread_ready_stride_cmd); + install_element (CONFIG_NODE, &no_thread_ready_stride_cmd); } if (terminal) Index: lib/thread.c =================================================================== RCS file: /var/cvsroot/quagga/lib/thread.c,v retrieving revision 1.5 diff -u -r1.5 thread.c --- lib/thread.c 23 Dec 2003 08:56:19 -0000 1.5 +++ lib/thread.c 30 Apr 2004 13:36:47 -0000 @@ -145,6 +145,79 @@ totals->max = a->max; } +DEFUN(thread_ready_stride, + thread_ready_stride_cmd, + "thread ready-stride <1-1000>", + "Thread commands\n" + "Stride for number of threads to add to ready list per scan\n" + "maximum thread count per thread type\n") +{ + u_int32_t stride; + + stride = strtol (argv[0], NULL, 10); + + if (stride < 1 || stride > 1000) + { + vty_out (vty, "Thread ready list stride is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* could not possibly occur, but lets not crash daemon + * because of a mistake in a generic vty command + */ + if (vty->master == NULL) + { + vty_out (vty, "Error, vty has no thread master!%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + vty->master->stride = stride; + + return CMD_SUCCESS; +} + +DEFUN(no_thread_ready_stride, + no_thread_ready_stride_cmd, + "no thread ready-stride <1-1000>", + NO_STR + "Thread commands\n" + "Stride for number of threads to add to ready list per scan\n" + "maximum thread count per thread type\n") +{ + u_int32_t stride = QUAGGA_THREAD_DEFAULT_STRIDE; + + if (argc == 1) + stride = strtol (argv[0], NULL, 10); + + if ( (argc == 1) && (stride < 1 || stride > 1000) ) + { + vty_out (vty, "Thread ready list stride is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Could not possibly occur, but lets not crash a daemon + * because of a mistake in a generic vty command + */ + if (vty->master == NULL) + { + vty_out (vty, "Error, no thread_master for vty!%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ( (argc == 1) && (stride != vty->master->stride) ) + { + vty_out (vty, "Current stride value is %d%s", + vty->t_read->master->stride, VTY_NEWLINE); + return CMD_WARNING; + } + + vty->master->stride = QUAGGA_THREAD_DEFAULT_STRIDE; + + return CMD_SUCCESS; +} + static void cpu_record_print(struct vty *vty, unsigned char filter) { @@ -252,12 +325,22 @@ struct thread_master * thread_master_create () { + struct thread_master *m; + if (cpu_record == NULL) { cpu_record = hash_create_size( 1011, cpu_record_hash_key, cpu_record_hash_cmp); } - return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER, + + m = (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master)); + + if (m == NULL) + return m; + + m->stride = QUAGGA_THREAD_DEFAULT_STRIDE; + + return m; } /* Add a new thread to the list. */ @@ -642,10 +725,10 @@ timer_wait = NULL; for (thread = m->timer.head; thread; thread = thread->next) { - if (! timer_wait) - timer_wait = &thread->u.sands; + if (!timer_wait) + timer_wait = &thread->u.sands; else if (timeval_cmp (thread->u.sands, *timer_wait) < 0) - timer_wait = &thread->u.sands; + timer_wait = &thread->u.sands; } if (m->timer.head) @@ -653,10 +736,10 @@ timer_min = *timer_wait; timer_min = timeval_subtract (timer_min, timer_now); if (timer_min.tv_sec < 0) - { - timer_min.tv_sec = 0; - timer_min.tv_usec = 10; - } + { + timer_min.tv_sec = 0; + timer_min.tv_usec = 10; + } timer_wait = &timer_min; } else @@ -682,10 +765,10 @@ timer_min = m->timer.head->u.sands; timer_min = timeval_subtract (timer_min, timer_now); if (timer_min.tv_sec < 0) - { - timer_min.tv_sec = 0; - timer_min.tv_usec = 10; - } + { + timer_min.tv_sec = 0; + timer_min.tv_usec = 10; + } *timer_val = timer_min; return timer_val; } @@ -703,27 +786,33 @@ return fetch; } +void +thread_add_ready (struct thread_master *m, struct thread_list *list, + struct thread *thread) +{ + thread_list_delete (list, thread); + thread_list_add (&m->ready, thread); + thread->type = THREAD_READY; +} + +/* Make ready IO threads */ int -thread_process_fd (struct thread_master *m, struct thread_list *list, - fd_set *fdset, fd_set *mfdset) +thread_ready_fd (struct thread_master *m, struct thread_list *list, + fd_set * fdset, fd_set * mfdset) { struct thread *thread; - struct thread *next; - int ready = 0; + int ready; - for (thread = list->head; thread; thread = next) + /* process no more than m->stride threads to prevent starvation */ + THREAD_MAX_LOOP (list, thread, ready, m->stride) { - next = thread->next; - if (FD_ISSET (THREAD_FD (thread), fdset)) - { - assert (FD_ISSET (THREAD_FD (thread), mfdset)); - FD_CLR(THREAD_FD (thread), mfdset); - thread_list_delete (list, thread); - thread_list_add (&m->ready, thread); - thread->type = THREAD_READY; - ready++; - } + { + assert (FD_ISSET (THREAD_FD (thread), mfdset)); + FD_CLR (THREAD_FD (thread), mfdset); + thread_add_ready (m, list, thread); + ready++; + } } return ready; } @@ -748,23 +837,32 @@ while (1) { - /* Normal event is the highest priority. */ - if ((thread = thread_trim_head (&m->event)) != NULL) - return thread_run (m, thread, fetch); + /* Normal event have highest priority per schedule run. */ + THREAD_MAX_LOOP(&m->event, thread, ready, m->stride) + { + thread_add_ready (m, &m->event, thread); + ready++; + } - /* Execute timer. */ + /* Timer events are next priority */ gettimeofday (&timer_now, NULL); +#ifdef TIMER_NO_SORT for (thread = m->timer.head; thread; thread = thread->next) - if (timeval_cmp (timer_now, thread->u.sands) >= 0) - { - thread_list_delete (&m->timer, thread); - return thread_run (m, thread, fetch); - } +#else /* !TIMER_NO_SORT */ + THREAD_MAX_LOOP (&m->timer, thread, ready, m->stride) +#endif /* TIMER_NO_SORT */ + { + if (timeval_cmp (timer_now, thread->u.sands) >= 0) + { + thread_add_ready (m, &m->timer, thread); + ready++; + } + } - /* If there are any ready threads, process top of them. */ + /* If there are any ready threads, process top of them. */ if ((thread = thread_trim_head (&m->ready)) != NULL) - return thread_run (m, thread, fetch); + return thread_run (m, thread, fetch); /* Structure copy. */ readfd = m->readfd; @@ -777,25 +875,25 @@ num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); if (num == 0) - continue; + continue; if (num < 0) - { - if (errno == EINTR) - continue; + { + if (errno == EINTR) + continue; + + zlog_warn ("select() error: %s", strerror (errno)); + return NULL; + } - zlog_warn ("select() error: %s", strerror (errno)); - return NULL; - } + /* Write thead. */ + ready = thread_ready_fd (m, &m->write, &writefd, &m->writefd); /* Normal priority read thead. */ - ready = thread_process_fd (m, &m->read, &readfd, &m->readfd); - - /* Write thead. */ - ready = thread_process_fd (m, &m->write, &writefd, &m->writefd); + ready = thread_ready_fd (m, &m->read, &readfd, &m->readfd); if ((thread = thread_trim_head (&m->ready)) != NULL) - return thread_run (m, thread, fetch); + return thread_run (m, thread, fetch); } } Index: lib/thread.h =================================================================== RCS file: /var/cvsroot/quagga/lib/thread.h,v retrieving revision 1.3 diff -u -r1.3 thread.h --- lib/thread.h 23 Dec 2003 08:56:19 -0000 1.3 +++ lib/thread.h 30 Apr 2004 13:36:47 -0000 @@ -38,6 +38,9 @@ int count; }; +/* Max amount of threads of a type to move onto ready list */ +#define QUAGGA_THREAD_DEFAULT_STRIDE 5 + /* Master of the theads. */ struct thread_master { @@ -51,6 +54,9 @@ fd_set writefd; fd_set exceptfd; unsigned long alloc; + + /* # of threads per thread-type to put on ready list at a time */ + unsigned int stride; }; /* Thread itself. */ @@ -124,6 +130,12 @@ } \ } while (0) +/* for every Thread in List, while Count is <= to Max */ +#define THREAD_MAX_LOOP(L, T, C, M) \ + for ((C) = 0, (T) = (L)->head; \ + ((T) != NULL) && ((C) <= (M)); \ + (T) = (T)->next) + #define THREAD_READ_OFF(thread) THREAD_OFF(thread) #define THREAD_WRITE_OFF(thread) THREAD_OFF(thread) #define THREAD_TIMER_OFF(thread) THREAD_OFF(thread) @@ -157,5 +169,7 @@ unsigned long thread_timer_remain_second (struct thread *); extern struct cmd_element show_thread_cpu_cmd; +extern struct cmd_element thread_ready_stride_cmd; +extern struct cmd_element no_thread_ready_stride_cmd; #endif /* _ZEBRA_THREAD_H */ Index: lib/vty.c =================================================================== RCS file: /var/cvsroot/quagga/lib/vty.c,v retrieving revision 1.14 diff -u -r1.14 vty.c --- lib/vty.c 16 Mar 2004 14:38:36 -0000 1.14 +++ lib/vty.c 30 Apr 2004 13:36:49 -0000 @@ -69,6 +69,9 @@ /* VTY server thread. */ vector Vvty_serv_thread; +/* Master of the threads. */ +static struct thread_master *master; + /* Current directory. */ char *vty_cwd = NULL; @@ -1564,15 +1567,16 @@ /* Allocate new vty structure and set up default values. */ vty = vty_new (); + vty->master = master; vty->fd = vty_sock; vty->type = VTY_TERM; vty->address = sockunion_su2str (su); if (no_password_check) { if (host.advanced) - vty->node = ENABLE_NODE; + vty->node = ENABLE_NODE; else - vty->node = VIEW_NODE; + vty->node = VIEW_NODE; } else vty->node = AUTH_NODE; @@ -1594,22 +1598,23 @@ vty->iac_sb_in_progress = 0; vty->sb_buffer = buffer_new (1024); - if (! no_password_check) + if (!no_password_check) { /* Vty is not available if password isn't set. */ if (host.password == NULL && host.password_encrypt == NULL) - { - vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE); - vty->status = VTY_CLOSE; - vty_close (vty); - return NULL; - } + { + vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE); + vty->status = VTY_CLOSE; + vty_close (vty); + return NULL; + } } /* Say hello to the world. */ vty_hello (vty); - if (! no_password_check) - vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + if (!no_password_check) + vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, + VTY_NEWLINE); /* Setting up terminal. */ vty_will_echo (vty); @@ -1662,21 +1667,21 @@ if (p->family == AF_INET && vty_accesslist_name) { if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) && - (access_list_apply (acl, p) == FILTER_DENY)) - { - char *buf; - zlog (NULL, LOG_INFO, "Vty connection refused from %s", - (buf = sockunion_su2str (&su))); - free (buf); - close (vty_sock); - - /* continue accepting connections */ - vty_event (VTY_SERV, accept_sock, NULL); - - prefix_free (p); + (access_list_apply (acl, p) == FILTER_DENY)) + { + char *buf; + zlog (NULL, LOG_INFO, "Vty connection refused from %s", + (buf = sockunion_su2str (&su))); + free (buf); + close (vty_sock); - return 0; - } + /* continue accepting connections */ + vty_event (VTY_SERV, accept_sock, NULL); + + prefix_free (p); + + return 0; + } } #ifdef HAVE_IPV6 @@ -1684,32 +1689,32 @@ if (p->family == AF_INET6 && vty_ipv6_accesslist_name) { if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) && - (access_list_apply (acl, p) == FILTER_DENY)) - { - char *buf; - zlog (NULL, LOG_INFO, "Vty connection refused from %s", - (buf = sockunion_su2str (&su))); - free (buf); - close (vty_sock); - - /* continue accepting connections */ - vty_event (VTY_SERV, accept_sock, NULL); - - prefix_free (p); + (access_list_apply (acl, p) == FILTER_DENY)) + { + char *buf; + zlog (NULL, LOG_INFO, "Vty connection refused from %s", + (buf = sockunion_su2str (&su))); + free (buf); + close (vty_sock); - return 0; - } + /* continue accepting connections */ + vty_event (VTY_SERV, accept_sock, NULL); + + prefix_free (p); + + return 0; + } } #endif /* HAVE_IPV6 */ - + prefix_free (p); on = 1; - ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, - (char *) &on, sizeof (on)); + ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, + (char *) &on, sizeof (on)); if (ret < 0) - zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", - strerror (errno)); + zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", + strerror (errno)); vty = vty_create (vty_sock, &su); @@ -2356,8 +2361,6 @@ return vty->config; } -/* Master of the threads. */ -static struct thread_master *master; static void vty_event (enum event event, int sock, struct vty *vty) @@ -2367,19 +2370,19 @@ switch (event) { case VTY_SERV: - vty_serv_thread = thread_add_read (master, vty_accept, vty, sock); + vty_serv_thread = thread_add_read (vty->master, vty_accept, vty, sock); vector_set_index (Vvty_serv_thread, sock, vty_serv_thread); break; #ifdef VTYSH case VTYSH_SERV: - thread_add_read (master, vtysh_accept, vty, sock); + thread_add_read (vty->master, vtysh_accept, vty, sock); break; case VTYSH_READ: - thread_add_read (master, vtysh_read, vty, sock); + thread_add_read (vty->master, vtysh_read, vty, sock); break; #endif /* VTYSH */ case VTY_READ: - vty->t_read = thread_add_read (master, vty_read, vty, sock); + vty->t_read = thread_add_read (vty->master, vty_read, vty, sock); /* Time out treatment. */ if (vty->v_timeout) @@ -2387,12 +2390,12 @@ if (vty->t_timeout) thread_cancel (vty->t_timeout); vty->t_timeout = - thread_add_timer (master, vty_timeout, vty, vty->v_timeout); + thread_add_timer (vty->master, vty_timeout, vty, vty->v_timeout); } break; case VTY_WRITE: if (! vty->t_write) - vty->t_write = thread_add_write (master, vty_flush, vty, sock); + vty->t_write = thread_add_write (vty->master, vty_flush, vty, sock); break; case VTY_TIMEOUT_RESET: if (vty->t_timeout) @@ -2403,7 +2406,7 @@ if (vty->v_timeout) { vty->t_timeout = - thread_add_timer (master, vty_timeout, vty, vty->v_timeout); + thread_add_timer (vty->master, vty_timeout, vty, vty->v_timeout); } break; } @@ -2816,9 +2819,9 @@ { /* For further configuration read, preserve current directory. */ vty_save_cwd (); - + vtyvec = vector_init (VECTOR_MIN_SIZE); - + master = master_thread; /* Initilize server thread vector. */ Index: lib/vty.h =================================================================== RCS file: /var/cvsroot/quagga/lib/vty.h,v retrieving revision 1.3 diff -u -r1.3 vty.h --- lib/vty.h 12 Aug 2003 13:08:31 -0000 1.3 +++ lib/vty.h 30 Apr 2004 13:36:49 -0000 @@ -109,6 +109,9 @@ /* In configure mode. */ int config; + + /* Thread master */ + struct thread_master *master; /* Read and write thread. */ struct thread *t_read;