statemachine.c

00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include "statemachine.h"
00004 
00005 static void clear_pending_tasks (SMObject *object);
00006 static void state_change (SMObject *object, SMObjectState new_state);
00007 static void sm_object_set_property (GObject *object,
00008                                     guint prop_id,
00009                                     const GValue *value,
00010                                     GParamSpec *pspec);
00011 static void sm_object_get_property (GObject *object,
00012                                     guint prop_id,
00013                                     GValue *value,
00014                                     GParamSpec *pspec);
00015 enum
00016 {
00017   PROP_0,
00018   PROP_NAME
00019 };
00020 
00021 enum
00022 {
00023   STATE_CHANGED,
00024   ACQUISITION_FAILED,
00025   ACQUISITION_PROGRESS,
00026   LAST_SIGNAL
00027 };
00028 
00029 static guint sm_object_signals[LAST_SIGNAL] = { 0 };
00030 
00031 G_DEFINE_TYPE(SMObject, sm_object, G_TYPE_OBJECT)
00032 
00033 static void
00034 sm_object_init (SMObject *obj)
00035 {
00036   obj->state = SM_OBJECT_STATE_SHUTDOWN;
00037 }
00038 
00039 static void
00040 sm_object_class_init (SMObjectClass *klass)
00041 {
00042   GObjectClass *object_class;
00043   
00044   object_class = G_OBJECT_CLASS (klass);
00045 
00046   object_class->set_property = sm_object_set_property;
00047   object_class->get_property = sm_object_get_property;
00048   
00049   g_object_class_install_property (object_class,
00050                                    PROP_NAME,
00051                                    g_param_spec_string ("name",
00052                                                         "name",
00053                                                         "name",
00054                                                         NULL,
00055                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
00056   sm_object_signals[STATE_CHANGED] =
00057     g_signal_new ("state-changed",
00058                   G_OBJECT_CLASS_TYPE (klass),
00059                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
00060                   0,
00061                   NULL, NULL,
00062                   g_cclosure_marshal_VOID__STRING,
00063                   G_TYPE_NONE, 1, G_TYPE_STRING);
00064   sm_object_signals[ACQUISITION_PROGRESS] =
00065     g_signal_new ("acquisition-progress",
00066                   G_OBJECT_CLASS_TYPE (klass),
00067                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
00068                   0,
00069                   NULL, NULL,
00070                   g_cclosure_marshal_VOID__DOUBLE,
00071                   G_TYPE_NONE, 1, G_TYPE_DOUBLE);
00072   sm_object_signals[ACQUISITION_FAILED] =
00073     g_signal_new ("acquisition-failed",
00074                   G_OBJECT_CLASS_TYPE (klass),
00075                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
00076                   0,
00077                   NULL, NULL,
00078                   g_cclosure_marshal_VOID__VOID,
00079                   G_TYPE_NONE, 0);
00080 }
00081 
00082 /* This should really be standard. */
00083 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
00084 
00085 GQuark
00086 sm_error_quark (void)
00087 {
00088   static GQuark ret = 0;
00089   if (!ret)
00090     ret = g_quark_from_static_string ("SMObjectErrorQuark");
00091   return ret;
00092 }
00093 
00094 GType
00095 sm_object_state_get_type (void)
00096 {
00097   static GType etype = 0;
00098 
00099   if (etype == 0)
00100     {
00101       static const GEnumValue values[] =
00102         {
00103 
00104           ENUM_ENTRY (SM_OBJECT_STATE_SHUTDOWN, "Shutdown"),
00105           ENUM_ENTRY (SM_OBJECT_STATE_INITIALIZED, "Loading"),
00106           ENUM_ENTRY (SM_OBJECT_STATE_ACQUIRED, "Acquired"),
00107           ENUM_ENTRY (SM_OBJECT_STATE_OPERATING, "Operating"),
00108           { 0, 0, 0 }
00109         };
00110 
00111       etype = g_enum_register_static ("SMObjectState", values);
00112     }
00113 
00114   return etype;
00115 }
00116 
00117 GType
00118 sm_error_get_type (void)
00119 {
00120   static GType etype = 0;
00121 
00122   if (etype == 0)
00123     {
00124       static const GEnumValue values[] =
00125         {
00126 
00127           ENUM_ENTRY (SM_ERROR_INVALID_STATE, "InvalidState"),
00128           ENUM_ENTRY (SM_ERROR_NAME_IN_USE, "NameInUse"),
00129           { 0, 0, 0 }
00130         };
00131 
00132       g_assert (SM_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
00133 
00134       etype = g_enum_register_static ("SMError", values);
00135     }
00136 
00137   return etype;
00138 }
00139 
00140 static void
00141 sm_object_set_property (GObject *object,
00142                         guint prop_id,
00143                         const GValue *value,
00144                         GParamSpec *pspec)
00145 {
00146   SMObject *sm = SM_OBJECT (object);
00147 
00148   switch (prop_id)
00149     {
00150     case PROP_NAME:
00151       sm->name = g_strdup (g_value_get_string (value));
00152       break;
00153     default:
00154       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
00155       break;
00156     }
00157 }
00158 
00159 static void 
00160 sm_object_get_property (GObject *object,
00161                         guint prop_id,
00162                         GValue *value,
00163                         GParamSpec *pspec)
00164 {
00165   SMObject *sm= SM_OBJECT (object);
00166 
00167   switch (prop_id)
00168     {
00169     case PROP_NAME:
00170       g_value_set_string (value, sm->name);
00171       break;
00172     default:
00173       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
00174       break;
00175     }
00176 }
00177 
00178 static const char *
00179 state_to_string (SMObjectState state)
00180 {
00181   GEnumValue *value;
00182   GEnumClass *prop_class;
00183   const char *ret;
00184   
00185   prop_class = g_type_class_ref (SM_TYPE_OBJECT_STATE);
00186   value = g_enum_get_value (prop_class, state);
00187   ret = value->value_nick;
00188 
00189   g_type_class_unref (prop_class);
00190   return ret;
00191 }
00192 
00193 static void
00194 queue_task (SMObject *object, guint delay, GSourceFunc func)
00195 {
00196   guint id;
00197   id = g_timeout_add (delay, func, object);
00198   object->pending_tasks = g_slist_prepend (object->pending_tasks, GUINT_TO_POINTER (id));
00199 }
00200 
00201 static gboolean
00202 idle_state_change (gpointer data)
00203 {
00204   SMObject *object = data;
00205 
00206   g_print ("doing idle state change for %s to %s\n",
00207            object->name, state_to_string (object->requested_state));
00208   state_change (object, object->requested_state);
00209   return FALSE;
00210 }
00211 
00212 static gboolean
00213 idle_further_acquire (gpointer data)
00214 {
00215   SMObject *object = data;
00216 
00217   g_print ("doing idle acquisition for machine %s\n", object->name);
00218   object->acquisition_progress += g_random_double_range (0.20, 0.7);
00219   if (object->acquisition_progress > 1.0)
00220     {
00221       object->acquisition_progress = 1.0;
00222       return FALSE;
00223     }
00224   else
00225     {
00226       g_signal_emit (object, sm_object_signals[ACQUISITION_PROGRESS], 0, object->acquisition_progress);
00227       return TRUE;
00228     }
00229 }
00230 
00231 static void
00232 clear_pending_tasks (SMObject *object)
00233 {
00234   GSList *tmp;
00235   for (tmp = object->pending_tasks; tmp; tmp = tmp->next)
00236     g_source_remove (GPOINTER_TO_UINT (tmp->data));
00237   g_slist_free (object->pending_tasks);
00238   object->pending_tasks = NULL;
00239 }
00240 
00241 static void
00242 state_change (SMObject *object, SMObjectState new_state)
00243 {
00244   g_signal_emit (object, sm_object_signals[STATE_CHANGED], 0,
00245                  state_to_string (new_state));
00246 
00247   clear_pending_tasks (object);
00248 
00249   if (new_state == SM_OBJECT_STATE_ACQUIRED)
00250     {
00251       object->acquisition_progress = 0.0;
00252       queue_task (object, 1000, idle_further_acquire);
00253     }
00254   else if (new_state == SM_OBJECT_STATE_INITIALIZED)
00255     {
00256       if (g_random_int_range (0, 2) == 0)
00257         {
00258           object->requested_state = SM_OBJECT_STATE_ACQUIRED;
00259           queue_task (object, 3000, idle_state_change);
00260         }
00261     }
00262   
00263   object->state = new_state;
00264 }
00265 
00266 gboolean
00267 sm_object_get_info (SMObject *object, char **name, char **state, GError **error)
00268 {
00269   *name= g_strdup (object->name);
00270   *state = g_strdup (state_to_string (object->state));
00271   return TRUE;
00272 }
00273 
00274 gboolean
00275 sm_object_start (SMObject *object, GError **error)
00276 {
00277   if (object->state != SM_OBJECT_STATE_SHUTDOWN)
00278     {
00279       g_set_error (error,
00280                    SM_ERROR,
00281                    SM_ERROR_INVALID_STATE,
00282                    "%s",
00283                    "Can't start from non-shutdown state");
00284       return FALSE;
00285     }
00286   state_change (object, SM_OBJECT_STATE_INITIALIZED);
00287   return TRUE;
00288 }
00289 
00290 gboolean
00291 sm_object_shutdown (SMObject *object, GError **error)
00292 {
00293   if (object->state == SM_OBJECT_STATE_SHUTDOWN)
00294     {
00295       g_set_error (error,
00296                    SM_ERROR,
00297                    SM_ERROR_INVALID_STATE,
00298                    "%s",
00299                    "Can't shutdown from shutdown state");
00300       return FALSE;
00301     }
00302   state_change (object, SM_OBJECT_STATE_SHUTDOWN);
00303   return TRUE;
00304 }
00305 
00306 gboolean
00307 sm_object_reinitialize (SMObject *object, GError **error)
00308 {
00309   if (object->state != SM_OBJECT_STATE_ACQUIRED
00310       && object->state != SM_OBJECT_STATE_OPERATING)
00311     {
00312       g_set_error (error,
00313                    SM_ERROR,
00314                    SM_ERROR_INVALID_STATE,
00315                    "Can't reinitialize from state %d",
00316                    object->state);
00317       return FALSE;
00318     }
00319   state_change (object, SM_OBJECT_STATE_INITIALIZED);
00320   return TRUE;
00321 }
00322 
00323 gboolean
00324 sm_object_reacquire (SMObject *object, GError **error)
00325 {
00326   if (object->state == SM_OBJECT_STATE_ACQUIRED)
00327     {
00328       g_set_error (error,
00329                    SM_ERROR,
00330                    SM_ERROR_INVALID_STATE,
00331                    "Can't reacquire from state %d",
00332                    object->state);
00333       return FALSE;
00334     }
00335   state_change (object, SM_OBJECT_STATE_ACQUIRED);
00336   return TRUE;
00337 }
00338 
00339 gboolean
00340 sm_object_get_acquiring_progress (SMObject *object, gdouble *out, GError **error)
00341 {
00342   if (object->state != SM_OBJECT_STATE_ACQUIRED)
00343     {
00344       g_set_error (error,
00345                    SM_ERROR,
00346                    SM_ERROR_INVALID_STATE,
00347                    "Can't get progress from state %d",
00348                    object->state);
00349       return FALSE;
00350     }
00351   *out = object->acquisition_progress;
00352   return TRUE;
00353 }

Generated on Tue Feb 24 16:47:59 2009 for D-BUSGLibBindings by  doxygen 1.5.1