int fib (x, depth) { int a, b; waste_time (); log_transition (&context, depth); if (x < 2) return 1; else { a = fib (x-1, depth+1); log_transition (&context, depth); b = fib (x-2, depth+1); log_transition (&context, depth); return a+b; } }
/* * The method thread executes a service method to effect a state transition. * The next_state of info->sf_id should be non-_NONE on entrance, and it will * be _NONE on exit (state will either be what next_state was (on success), or * it will be _MAINT (on error)). * * There are six classes of methods to consider: start & other (stop, refresh) * for each of "normal" services, wait services, and transient services. For * each, the method must be fetched from the repository & executed. fork()ed * methods must be waited on, except for the start method of wait services * (which must be registered with the wait subsystem via wait_register()). If * the method succeeded (returned 0), then for start methods its contract * should be recorded as the primary contract for the service. For other * methods, it should be abandoned. If the method fails, then depending on * the failure, either the method should be reexecuted or the service should * be put into maintenance. Either way the contract should be abandoned. */ void * method_thread(void *arg) { fork_info_t *info = arg; restarter_inst_t *inst; scf_handle_t *local_handle; scf_instance_t *s_inst = NULL; int r, exit_code; boolean_t retryable; const char *aux; assert(0 <= info->sf_method_type && info->sf_method_type <= 2); /* Get (and lock) the restarter_inst_t. */ inst = inst_lookup_by_id(info->sf_id); assert(inst->ri_method_thread != 0); assert(instance_in_transition(inst) == 1); /* * We cannot leave this function with inst in transition, because * protocol.c withholds messages for inst otherwise. */ log_framework(LOG_DEBUG, "method_thread() running %s method for %s.\n", method_names[info->sf_method_type], inst->ri_i.i_fmri); local_handle = libscf_handle_create_bound_loop(); rebind_retry: /* get scf_instance_t */ switch (r = libscf_fmri_get_instance(local_handle, inst->ri_i.i_fmri, &s_inst)) { case 0: break; case ECONNABORTED: libscf_handle_rebind(local_handle); goto rebind_retry; case ENOENT: /* * It's not there, but we need to call this so protocol.c * doesn't think it's in transition anymore. */ (void) restarter_instance_update_states(local_handle, inst, inst->ri_i.i_state, RESTARTER_STATE_NONE, RERR_NONE, NULL); goto out; case EINVAL: case ENOTSUP: default: bad_error("libscf_fmri_get_instance", r); } inst->ri_m_inst = s_inst; inst->ri_mi_deleted = B_FALSE; retry: if (info->sf_method_type == METHOD_START) log_transition(inst, START_REQUESTED); r = method_run(&inst, info->sf_method_type, &exit_code); if (r == 0 && exit_code == 0) { /* Success! */ assert(inst->ri_i.i_next_state != RESTARTER_STATE_NONE); /* * When a stop method succeeds, remove the primary contract of * the service, unless we're going to offline, in which case * retain the contract so we can transfer inherited contracts to * the replacement service. */ if (info->sf_method_type == METHOD_STOP && inst->ri_i.i_primary_ctid != 0) { if (inst->ri_i.i_next_state == RESTARTER_STATE_OFFLINE) inst->ri_i.i_primary_ctid_stopped = 1; else method_remove_contract(inst, B_TRUE, B_TRUE); } /* * We don't care whether the handle was rebound because this is * the last thing we do with it. */ (void) restarter_instance_update_states(local_handle, inst, inst->ri_i.i_next_state, RESTARTER_STATE_NONE, info->sf_event_type, NULL); (void) update_fault_count(inst, FAULT_COUNT_RESET); goto out; } /* Failure. Retry or go to maintenance. */ if (r != 0 && r != EAGAIN) { retryable = B_FALSE; } else { switch (exit_code) { case SMF_EXIT_ERR_CONFIG: case SMF_EXIT_ERR_NOSMF: case SMF_EXIT_ERR_PERM: case SMF_EXIT_ERR_FATAL: retryable = B_FALSE; break; default: retryable = B_TRUE; } } if (retryable && update_fault_count(inst, FAULT_COUNT_INCR) != 1) goto retry; /* maintenance */ if (r == ELOOP) log_transition(inst, START_FAILED_REPEATEDLY); else if (r == ERANGE) log_transition(inst, START_FAILED_TIMEOUT_FATAL); else if (exit_code == SMF_EXIT_ERR_CONFIG) log_transition(inst, START_FAILED_CONFIGURATION); else if (exit_code == SMF_EXIT_ERR_FATAL) log_transition(inst, START_FAILED_FATAL); else log_transition(inst, START_FAILED_OTHER); if (r == ELOOP) aux = "restarting_too_quickly"; else if (retryable) aux = "fault_threshold_reached"; else aux = "method_failed"; (void) restarter_instance_update_states(local_handle, inst, RESTARTER_STATE_MAINT, RESTARTER_STATE_NONE, RERR_FAULT, (char *)aux); if (!method_is_transient(inst, info->sf_method_type) && inst->ri_i.i_primary_ctid != 0) method_remove_contract(inst, B_TRUE, B_TRUE); out: inst->ri_method_thread = 0; MUTEX_UNLOCK(&inst->ri_lock); (void) pthread_cond_broadcast(&inst->ri_method_cv); scf_instance_destroy(s_inst); scf_handle_destroy(local_handle); startd_free(info, sizeof (fork_info_t)); return (NULL); }