Пример #1
0
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;
    }
}
Пример #2
0
/*
 * 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);
}