#ifndef MODULE_LIFECYCLE_H_ #define MODULE_LIFECYCLE_H_ #include #include #include enum module_lifecycle { LC_UNINIT, LC_RUNNING, LC_STOPPED, LC_SUSPENDED, LC_ERROR, }; enum module_lifecycle_mode { ML_MODE_NONE, ML_MODE_POWER, ML_MODE_SUSPEND, }; struct module_lifecycle_ops { int (*do_init)(void); int (*do_start)(void); int (*do_stop)(void); }; struct module_lifecycle_cfg { enum module_lifecycle_mode mode; enum module_state stopped_state; }; struct module_lifecycle_ctx { enum module_lifecycle state; const struct module_lifecycle_cfg *cfg; const struct module_lifecycle_ops *ops; }; static inline bool module_lifecycle_is_running( const struct module_lifecycle_ctx *ctx) { return ctx->state == LC_RUNNING; } static inline bool module_lifecycle_is_initialized( const struct module_lifecycle_ctx *ctx) { return (ctx->state != LC_UNINIT) && (ctx->state != LC_ERROR); } static inline bool module_lifecycle_reports_stopped_state( const struct module_lifecycle_ctx *ctx) { return ctx->cfg->mode != ML_MODE_NONE; } static inline int module_lifecycle_report_state( struct module_lifecycle_ctx *ctx, enum module_lifecycle state) { switch (state) { case LC_RUNNING: module_set_state(MODULE_STATE_READY); return 0; case LC_STOPPED: if (!module_lifecycle_reports_stopped_state(ctx)) { return 0; } module_set_state(ctx->cfg->stopped_state); return 0; case LC_SUSPENDED: module_set_state(MODULE_STATE_SUSPENDED); return 0; case LC_ERROR: module_set_state(MODULE_STATE_ERROR); return 0; case LC_UNINIT: default: return -EINVAL; } } static inline int module_lifecycle_fail(struct module_lifecycle_ctx *ctx, int err) { ctx->state = LC_ERROR; (void)module_lifecycle_report_state(ctx, LC_ERROR); return err ? err : -EIO; } static inline int module_lifecycle_do_init(struct module_lifecycle_ctx *ctx) { int err = ctx->ops->do_init(); if (err) { return module_lifecycle_fail(ctx, err); } return 0; } static inline int module_lifecycle_do_start(struct module_lifecycle_ctx *ctx, enum module_lifecycle target) { int err = ctx->ops->do_start(); if (err) { return module_lifecycle_fail(ctx, err); } ctx->state = target; return module_lifecycle_report_state(ctx, target); } static inline int module_lifecycle_do_stop(struct module_lifecycle_ctx *ctx, enum module_lifecycle target) { int err = ctx->ops->do_stop(); if (err) { return module_lifecycle_fail(ctx, err); } ctx->state = target; return module_lifecycle_report_state(ctx, target); } static inline int module_set_lifecycle(struct module_lifecycle_ctx *ctx, enum module_lifecycle target) { if ((ctx == NULL) || (ctx->cfg == NULL) || (ctx->ops == NULL) || (ctx->ops->do_init == NULL) || (ctx->ops->do_start == NULL) || (ctx->ops->do_stop == NULL)) { return -EINVAL; } if (ctx->state == LC_ERROR) { return -EFAULT; } if (ctx->state == target) { return 0; } if (target == LC_ERROR) { return module_lifecycle_fail(ctx, -EIO); } switch (ctx->state) { case LC_UNINIT: if (target == LC_RUNNING) { int err = module_lifecycle_do_init(ctx); if (err) { return err; } ctx->state = LC_STOPPED; return module_lifecycle_do_start(ctx, LC_RUNNING); } if (target == LC_STOPPED) { int err = module_lifecycle_do_init(ctx); if (err) { return err; } ctx->state = LC_STOPPED; return module_lifecycle_report_state(ctx, LC_STOPPED); } break; case LC_RUNNING: if ((target == LC_STOPPED) || (target == LC_SUSPENDED)) { return module_lifecycle_do_stop(ctx, target); } break; case LC_STOPPED: case LC_SUSPENDED: if (target == LC_RUNNING) { return module_lifecycle_do_start(ctx, LC_RUNNING); } break; case LC_ERROR: default: break; } return -EPERM; } #endif /* MODULE_LIFECYCLE_H_ */