Changeset 5559712 in mainline


Ignore:
Timestamp:
2019-08-03T09:28:50Z (5 years ago)
Author:
Matthieu Riolo <matthieu.riolo@…>
Children:
c0e4fc50
Parents:
2dda1d4
git-author:
Michal Koutný <xm.koutny+hos@…> (2015-05-07 11:49:47)
git-committer:
Matthieu Riolo <matthieu.riolo@…> (2019-08-03 09:28:50)
Message:

sysman: Naive autostart instrumentation of locsrv

  • Add IPC_FLAG_AUTOSTART flag.
  • libsysman: sysman's broker and control API.
  • Simple implementation of service unit, exposee verification is missing.
  • Simple mapping of exposee to unit name in locsrv.
  • Temporary debug prints in locsrv.

Conflicts:

boot/Makefile.common
boot/arch/amd64/Makefile.inc
uspace/lib/c/include/ipc/services.h
uspace/srv/locsrv/locsrv.c

Location:
uspace
Files:
15 added
23 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/include/ipc/common.h

    r2dda1d4 r5559712  
    3939#include <abi/ipc/ipc.h>
    4040
    41 #define IPC_FLAG_BLOCKING  0x01
     41#define IPC_FLAG_BLOCKING   0x01
     42// TODO autostart flag may be united with blocking, this should be later made
     43//      implicit, documented or refactor pairs of xxx and xxx_blocking methods
     44#define IPC_FLAG_AUTOSTART  0x02
    4245
    4346typedef ipc_data_t ipc_call_t;
  • uspace/lib/c/include/ipc/services.h

    r2dda1d4 r5559712  
    4040#include <abi/fourcc.h>
    4141
     42/** Name of service brokered by NS */
    4243typedef enum {
    4344        SERVICE_NONE       = 0,
     
    4546        SERVICE_VFS        = FOURCC('v', 'f', 's', ' '),
    4647        SERVICE_LOC        = FOURCC('l', 'o', 'c', ' '),
     48        SERVICE_SYSMAN     = FOURCC('s', 'y', 's', 'm'),
    4749        SERVICE_LOGGER     = FOURCC('l', 'o', 'g', 'g'),
    4850        SERVICE_DEVMAN     = FOURCC('d', 'e', 'v', 'n'),
     
    6466#define SERVICE_NAME_VOLSRV   "volsrv"
    6567
     68#define LOC_DEVICE_NAMESPACE         "devices"
     69#define LOC_UNIT_NAMESPACE_SEPARATOR "__"
     70
    6671#endif
    6772
  • uspace/srv/devman/devman.h

    r2dda1d4 r5559712  
    4848#define NAME "devman"
    4949
    50 #define LOC_DEVICE_NAMESPACE "devices"
    5150#define LOC_SEPARATOR '\\'
    5251
  • uspace/srv/devman/loc.c

    r2dda1d4 r5559712  
    3131 */
    3232
     33#include <ipc/services.h>
    3334#include <loc.h>
    3435#include <stdio.h>
  • uspace/srv/locsrv/Makefile

    r2dda1d4 r5559712  
    2929
    3030USPACE_PREFIX = ../..
     31LIBS = $(LIBSYSMAN_PREFIX)/libsysman.a
     32EXTRA_CFLAGS += -I$(LIBSYSMAN_PREFIX)/include
    3133BINARY = locsrv
    3234STATIC_NEEDED = y
  • uspace/srv/locsrv/locsrv.c

    r2dda1d4 r5559712  
    3636 */
    3737
     38#include <assert.h>
     39#include <async.h>
     40#include <errno.h>
     41#include <ipc/loc.h>
    3842#include <ipc/services.h>
    39 #include <ns.h>
    40 #include <async.h>
    41 #include <stdio.h>
    42 #include <errno.h>
    43 #include <stdbool.h>
    4443#include <fibril_synch.h>
    4544#include <macros.h>
     45#include <ns.h>
     46#include <stdbool.h>
     47#include <stdio.h>
    4648#include <stdlib.h>
    4749#include <str.h>
    4850#include <str_error.h>
    49 #include <ipc/loc.h>
    50 #include <assert.h>
     51#include <sysman/broker.h>
     52#include <sysman/ctl.h>
    5153
    5254#include "category.h"
     
    331333        free(service->name);
    332334        free(service);
     335}
     336
     337static int loc_service_request_start(const char *ns_name, const char *name)
     338{
     339        char *service_name = NULL;
     340
     341        if (str_cmp(ns_name, LOC_DEVICE_NAMESPACE) == 0) {
     342                asprintf(&service_name, "%s", SERVICE_NAME_DEVMAN);
     343        } else if (str_cmp(ns_name, "") == 0) {
     344                asprintf(&service_name, "%s", name);
     345        } else {
     346                asprintf(&service_name, "%s%s%s",
     347                    ns_name, LOC_UNIT_NAMESPACE_SEPARATOR, name);
     348        }
     349        if (service_name == NULL) {
     350                return ENOMEM;
     351        }
     352
     353        char *unit_name;
     354        asprintf(&unit_name, "%s%c%s",
     355            service_name, UNIT_NAME_SEPARATOR, UNIT_SVC_TYPE_NAME);
     356        if (unit_name == NULL) {
     357                free(service_name);
     358                return ENOMEM;
     359        }
     360
     361        printf("%s(%s) before\n", __func__, unit_name);
     362        int rc = sysman_unit_start(unit_name, IPC_FLAG_BLOCKING);
     363        printf("%s(%s) after %i\n", __func__, unit_name, rc);
     364        free(unit_name);
     365        free(service_name);
     366        return rc;
    333367}
    334368
     
    531565
    532566        list_append(&service->server_services, &service->server->services);
     567       
     568        printf("%s: broadcast new service '%s/%s'\n", NAME, namespace->name,
     569            service->name);
    533570
    534571        fibril_mutex_unlock(&service->server->services_mutex);
     
    542579 *
    543580 */
    544 static void loc_service_unregister(ipc_call_t *icall, loc_server_t *server)
     581static void loc_service_unregister(ipc_callid_t iid, ipc_call_t *icall,
     582    loc_server_t *server)
    545583{
    546584        loc_service_t *svc;
     
    762800        fibril_mutex_lock(&services_list_mutex);
    763801        const loc_service_t *svc;
    764 
     802        int flags = ipc_get_arg1(*icall);
     803       
    765804recheck:
    766805
     
    771810
    772811        /*
    773          * Device was not found.
     812         * Service was not found.
    774813         */
    775814        if (svc == NULL) {
    776                 if (ipc_get_arg1(icall) & IPC_FLAG_BLOCKING) {
    777                         /* Blocking lookup */
     815                printf("%s: service '%s/%s' not found\n", NAME, ns_name, name);
     816                if (flags & (IPC_FLAG_AUTOSTART | IPC_FLAG_BLOCKING)) {
     817                        /* TODO:
     818                         * consider non-blocking service start, return
     819                         * some dummy id and block only after connection
     820                         * request (actually makes more sense as those who asks
     821                         * for ID might be someone else than those connecting)
     822                         */
     823                        if (flags & IPC_FLAG_AUTOSTART) {
     824                                rc = loc_service_request_start(ns_name, name);
     825                                if (rc != EOK) {
     826                                        goto finish;
     827                                }
     828                        }
     829
    778830                        fibril_condvar_wait(&services_list_cv,
    779831                            &services_list_mutex);
    780832                        goto recheck;
    781833                }
    782 
    783                 async_answer_0(icall, ENOENT);
    784                 free(ns_name);
    785                 free(name);
    786                 fibril_mutex_unlock(&services_list_mutex);
    787                 return;
    788         }
    789 
    790         async_answer_1(icall, EOK, svc->id);
    791 
     834                rc = ENOENT;
     835        } else {
     836                printf("%s: service '%s/%s' FOUND\n", NAME, ns_name, name);
     837                rc = EOK;
     838        }
     839
     840finish:
     841        if (rc == EOK) {
     842                async_answer_1(iid, EOK, svc->id);
     843        } else {
     844                async_answer_0(iid, rc);
     845        }
     846       
    792847        fibril_mutex_unlock(&services_list_mutex);
    793848        free(ns_name);
     
    15651620        if (rc != EOK) {
    15661621                printf("%s: Error while registering broker service: %s\n", NAME, str_error(rc));
     1622
     1623        /* Let sysman know we are broker */
     1624        printf("%s: sysman_broker_register : pre\n", NAME);
     1625        rc = sysman_broker_register();
     1626        printf("%s: sysman_broker_register : post\n", NAME);
     1627        if (rc != EOK) {
     1628                printf("%s: Error registering at sysman (%i)\n", NAME, rc);
    15671629                return rc;
    15681630        }
  • uspace/srv/sysman/Makefile

    r2dda1d4 r5559712  
    3030USPACE_PREFIX = ../..
    3131LIBS = $(LIBCONF_PREFIX)/libconf.a
    32 EXTRA_CFLAGS += -I. -I./units -I$(LIBCONF_PREFIX)/include
     32EXTRA_CFLAGS += -I. \
     33        -I./units \
     34        -I$(LIBCONF_PREFIX)/include \
     35        -I$(LIBSYSMAN_PREFIX)/include
    3336BINARY = sysman
    3437STATIC_NEEDED = y
     
    3639SOURCES = \
    3740        configuration.c \
     41        connection_broker.c \
     42        connection_ctl.c \
    3843        dep.c \
    3944        job.c \
     
    4449        units/unit_mnt.c \
    4550        units/unit_tgt.c \
     51        units/unit_svc.c \
    4652        util.c
    4753
  • uspace/srv/sysman/configuration.c

    r2dda1d4 r5559712  
    148148}
    149149
     150/** Remove all uncommited units and edges from configuratio
     151 *
     152 * Memory used by removed object is released.
     153 */
    150154void configuration_rollback(void)
    151155{
     
    186190 *
    187191 * @return EOK      on success
    188  * @return ENONENT  when one or more resolution fails, information is logged
     192 * @return ENOENT  when one or more resolution fails, information is logged
    189193 */
    190194int configuration_resolve_dependecies(void)
  • uspace/srv/sysman/dep.c

    r2dda1d4 r5559712  
    3636static void dep_dependency_init(unit_dependency_t *dep)
    3737{
     38        memset(dep, 0, sizeof(*dep));
    3839        link_initialize(&dep->dependants);
    3940        link_initialize(&dep->dependencies);
    4041
    41         dep->dependency_name = NULL;
    4242        dep->state = DEP_EMBRYO;
    4343}
  • uspace/srv/sysman/job.c

    r2dda1d4 r5559712  
    7373        assert(job);
    7474        assert(u);
     75        memset(job, 0, sizeof(*job));
    7576
    7677        link_initialize(&job->job_queue);
     
    101102                return false;
    102103        }
    103 }
    104 
    105 static bool job_is_runnable(job_t *job)
    106 {
    107         return job->state == JOB_QUEUED && job->blocking_jobs == 0;
    108104}
    109105
     
    126122}
    127123
    128 
    129 
    130 
    131124static void job_destroy(job_t **job_ptr)
    132125{
     
    145138        free(job);
    146139        *job_ptr = NULL;
     140}
     141
     142static bool job_is_runnable(job_t *job)
     143{
     144        return job->state == JOB_QUEUED && job->blocking_jobs == 0;
     145}
     146
     147/** Pop next runnable job
     148 *
     149 * @return runnable job or NULL when there's none
     150 */
     151static job_t *job_queue_pop_runnable(void)
     152{
     153        job_t *result = NULL;
     154
     155        /* Select first runnable job */
     156        list_foreach(job_queue, job_queue, job_t, candidate) {
     157                if (job_is_runnable(candidate)) {
     158                        result = candidate;
     159                        break;
     160                }
     161        }
     162        if (result) {
     163                /* Remove job from queue and pass reference to caller */
     164                list_remove(&result->job_queue);
     165                result->state = JOB_DEQUEUED;
     166        }
     167
     168        return result;
    147169}
    148170
     
    163185                        /*
    164186                         * Currently we have strict strategy not permitting
    165                          * multiple jobs for one unit in the queue.
     187                         * multiple jobs for one unit in the queue at a time.
    166188                         */
    167189                        if ((*new_job_it)->unit == queued_job->unit) {
    168190                                sysman_log(LVL_ERROR,
    169                                     "Cannot queue multiple jobs foor unit '%s'",
     191                                    "Cannot queue multiple jobs for unit '%s'",
    170192                                    unit_name((*new_job_it)->unit));
    171193                                return EEXIST;
     
    184206}
    185207
    186 /** Pop next runnable job
    187  *
    188  * @return runnable job or NULL when there's none
    189  */
    190 job_t *job_queue_pop_runnable(void)
    191 {
    192         job_t *result = NULL;
    193         link_t *first_link = list_first(&job_queue);
    194         bool first_iteration = true;
    195 
    196         list_foreach_safe(job_queue, cur_link, next_link) {
    197                 result = list_get_instance(cur_link, job_t, job_queue);
    198                 if (job_is_runnable(result)) {
    199                         break;
    200                 } else if (!first_iteration && cur_link == first_link) {
    201                         result = NULL;
    202                         break;
    203                 } else {
    204                         /*
    205                          * We make no assuptions about ordering of jobs in the
    206                          * queue, so just move the job to the end of the queue.
    207                          * If there are exist topologic ordering, eventually
    208                          * jobs will be reordered. Furthermore when if there
    209                          * exists any runnable job, it's always found.
    210                          */
    211                         list_remove(cur_link);
    212                         list_append(cur_link, &job_queue);
    213                 }
    214                 first_iteration = false;
    215         }
    216 
    217         if (result) {
    218                 /* Remove job from queue and pass refernce to caller */
    219                 list_remove(&result->job_queue);
    220                 result->state = JOB_DEQUEUED;
    221         }
    222 
    223         return result;
     208/** Process all jobs that aren't transitively blocked
     209 *
     210 * Job can be blocked either by another job or by an incoming event, that will
     211 * be queued after this job_queue_process call.
     212 *
     213 * TODO Write down rules from where this function can be called, to avoid stack
     214 *      overflow.
     215 */
     216void job_queue_process(void)
     217{
     218        job_t *job;
     219        while ((job = job_queue_pop_runnable())) {
     220                job_run(job);
     221                job_del_ref(&job);
     222        }
    224223}
    225224
     
    242241         */
    243242        fifo_push(jobs_fifo, main_job);
    244         job_t *job;
    245243        job_add_ref(main_job);
    246         while ((job = fifo_pop(jobs_fifo)) != NULL) {
    247                 /* No refcount increase, pass it to the closure */
    248                 dyn_array_append(job_closure, job_ptr_t, job);
     244        while (jobs_fifo.head != jobs_fifo.tail) {
     245                job_t *job = fifo_pop(jobs_fifo);
     246               
     247                // TODO more sophisticated check? (unit that is in transitional
     248                //      state cannot have currently multiple jobs queued)
     249                if (job->target_state == job->unit->state) {
     250                        /*
     251                         * Job would do nothing, finish it on spot.
     252                         * No need to continue BFS search from it.
     253                         */
     254                        job->retval = JOB_OK;
     255                        job_finish(job);
     256                        job_del_ref(&job);
     257                        continue;
     258                } else {
     259                        /* No refcount increase, pass it to the closure */
     260                        dyn_array_append(job_closure, job_ptr_t, job);
     261                }
    249262
    250263                /* Traverse dependencies edges */
     
    379392        /* Add reference for the event */
    380393        job_add_ref(job);
    381         sysman_raise_event(&sysman_event_job_changed, job);
    382 }
    383 
     394        sysman_raise_event(&sysman_event_job_finished, job);
     395}
     396
  • uspace/srv/sysman/job.h

    r2dda1d4 r5559712  
    3737#include "unit.h"
    3838
     39// TODO simplify queue states
    3940/** Run state of job */
    4041typedef enum {
     
    7778extern void job_queue_init(void);
    7879extern int job_queue_add_jobs(dyn_array_t *);
    79 extern job_t *job_queue_pop_runnable(void);
     80extern void job_queue_process(void);
    8081
    8182extern int job_create_closure(job_t *, dyn_array_t *);
  • uspace/srv/sysman/log.h

    r2dda1d4 r5559712  
    3737 * that would use logger as soon as it's ready.
    3838 */
    39 #define sysman_log(level, fmt, ...) printf("sysman: " fmt "\n", __VA_ARGS__)
     39#define sysman_log(level, fmt, ...) printf("sysman: " fmt "\n", ##__VA_ARGS__)
    4040
    4141#endif
  • uspace/srv/sysman/main.c

    r2dda1d4 r5559712  
    3030#include <errno.h>
    3131#include <fibril.h>
     32#include <ipc/sysman.h>
     33#include <macros.h>
     34#include <ns.h>
    3235#include <stddef.h>
    3336#include <stdio.h>
     
    3538
    3639#include "configuration.h"
     40#include "connection_broker.h"
     41#include "connection_ctl.h"
    3742#include "dep.h"
    3843#include "job.h"
     
    4348#define NAME "sysman"
    4449
    45 static void sysman_connection(ipc_callid_t callid, ipc_call_t *call, void *arg)
    46 {
    47         /* TODO handle client connections */
     50#define INITRD_DEVICE       "bd/initrd"
     51#define INITRD_MOUNT_POINT  "/"
     52#define INITRD_CFG_PATH     "/cfg/sysman"
     53
     54#define TARGET_INIT     "initrd.tgt"
     55#define TARGET_ROOTFS   "rootfs.tgt"
     56#define TARGET_DEFAULT  "default.tgt"
     57
     58#define UNIT_MNT_INITRD "initrd.mnt"
     59#define UNIT_CFG_INITRD "init.cfg"
     60
     61static const char *target_sequence[] = {
     62        TARGET_INIT,
     63        TARGET_ROOTFS,
     64        TARGET_DEFAULT,
     65        NULL
     66};
     67
     68/*
     69 * Forward declarations
     70 */
     71static void prepare_and_run_job(const char **target_name_ptr);
     72
     73/*
     74 * Static functions
     75 */
     76
     77static void sysman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     78{
     79        sysman_interface_t iface = IPC_GET_ARG1(*icall);
     80        switch (iface) {
     81        case SYSMAN_PORT_BROKER:
     82                sysman_connection_broker(iid, icall);
     83                break;
     84        case SYSMAN_PORT_CTL:
     85                sysman_connection_ctl(iid, icall);
     86                break;
     87        default:
     88                /* Unknown interface */
     89                async_answer_0(iid, ENOENT);
     90        }
    4891}
    4992
    5093/** Build hard coded configuration */
    51 static job_t *create_entry_configuration(void) {
    52         int result = EOK;
     94static int create_entry_configuration(void) {
     95        int rc;
    5396        unit_t *mnt_initrd = NULL;
    5497        unit_t *cfg_init = NULL;
    55         unit_t *tgt_default = NULL;
     98        unit_t *tgt_init = NULL;
    5699
    57100        mnt_initrd = unit_create(UNIT_MOUNT);
    58101        if (mnt_initrd == NULL) {
    59                 result = ENOMEM;
     102                rc = ENOMEM;
    60103                goto fail;
    61104        }
    62         mnt_initrd->name                 = str_dup("initrd.mnt");
    63         // TODO Use RDFMT
    64         CAST_MNT(mnt_initrd)->type       = str_dup("ext4fs");
    65         CAST_MNT(mnt_initrd)->mountpoint = str_dup("/");
    66         CAST_MNT(mnt_initrd)->device     = str_dup("bd/initrd");
     105        mnt_initrd->name                 = str_dup(UNIT_MNT_INITRD);
     106        CAST_MNT(mnt_initrd)->type       = str_dup(STRING(RDFMT));
     107        CAST_MNT(mnt_initrd)->mountpoint = str_dup(INITRD_MOUNT_POINT);
     108        CAST_MNT(mnt_initrd)->device     = str_dup(INITRD_DEVICE);
     109        CAST_MNT(mnt_initrd)->autostart  = false;
     110        CAST_MNT(mnt_initrd)->blocking   = true;
    67111
    68112        cfg_init = unit_create(UNIT_CONFIGURATION);
    69113        if (cfg_init == NULL) {
    70                 result = ENOMEM;
     114                rc = ENOMEM;
    71115                goto fail;
    72116        }
    73         cfg_init->name           = str_dup("init.cfg");
    74         CAST_CFG(cfg_init)->path = str_dup("/cfg/sysman");
     117        cfg_init->name           = str_dup(UNIT_CFG_INITRD);
     118        CAST_CFG(cfg_init)->path = str_dup(INITRD_CFG_PATH);
    75119       
    76         tgt_default = unit_create(UNIT_TARGET);
    77         if (tgt_default == NULL) {
    78                 result = ENOMEM;
     120        tgt_init = unit_create(UNIT_TARGET);
     121        if (tgt_init == NULL) {
     122                rc = ENOMEM;
    79123                goto fail;
    80124        }
    81         tgt_default->name = str_dup("default.tgt");
     125        tgt_init->name = str_dup(TARGET_INIT);
    82126       
    83127
     
    89133        configuration_add_unit(mnt_initrd);
    90134        configuration_add_unit(cfg_init);
    91         configuration_add_unit(tgt_default);
    92 
    93         result = dep_add_dependency(tgt_default, cfg_init);
    94         if (result != EOK) {
    95                 goto fail;
    96         }
    97 
    98         result = dep_add_dependency(cfg_init, mnt_initrd);
    99         if (result != EOK) {
    100                 goto fail;
     135        configuration_add_unit(tgt_init);
     136
     137        rc = dep_add_dependency(tgt_init, cfg_init);
     138        if (rc != EOK) {
     139                goto rollback;
     140        }
     141
     142        rc = dep_add_dependency(cfg_init, mnt_initrd);
     143        if (rc != EOK) {
     144                goto rollback;
    101145        }
    102146
    103147        configuration_commit();
    104148
    105         job_t *first_job = job_create(tgt_default, STATE_STARTED);
    106         if (first_job == NULL) {
    107                 goto fail;
    108         }
    109         return first_job;
     149        return EOK;
    110150
    111151fail:
    112         // TODO cannot destroy units after they're added to configuration
    113         unit_destroy(&tgt_default);
     152        unit_destroy(&tgt_init);
    114153        unit_destroy(&cfg_init);
    115154        unit_destroy(&mnt_initrd);
    116         return NULL;
    117 }
    118 
    119 static void first_job_handler(void *object, void *unused)
     155        return rc;
     156
     157rollback:
     158        configuration_rollback();
     159        return rc;
     160}
     161
     162static void sequence_job_handler(void *object, void *arg)
    120163{
    121164        job_t *job = object;
    122         sysman_log(LVL_DEBUG, "First job retval: %i.", job->retval);
     165        if (job->retval == JOB_FAILED) {
     166                sysman_log(LVL_ERROR, "Failed to start '%s'.", unit_name(job->unit));
     167                job_del_ref(&job);
     168                return;
     169        }
    123170        job_del_ref(&job);
     171       
     172        const char **target_name_ptr = arg;
     173        prepare_and_run_job(target_name_ptr + 1);
     174}
     175
     176static void prepare_and_run_job(const char **target_name_ptr)
     177{
     178        const char *target_name = *target_name_ptr;
     179
     180        if (target_name == NULL) {
     181                sysman_log(LVL_NOTE, "All initial units started.");
     182                return;
     183        }
     184
     185        /* Previous targets should have loaded new units */
     186        unit_t *tgt = configuration_find_unit_by_name(target_name);
     187        if (tgt == NULL) {
     188                sysman_log(LVL_ERROR,
     189                    "Expected unit '%s' not found in configuration.",
     190                    target_name);
     191                return;
     192        }
     193
     194        int rc = sysman_queue_job(tgt, STATE_STARTED, &sequence_job_handler,
     195            target_name_ptr);
     196
     197        if (rc != EOK) {
     198                sysman_log(LVL_FATAL, "Cannot create job for '%s'.", target_name);
     199        }
    124200}
    125201
     
    136212
    137213        /*
    138          * Create initial configuration while we are in a single fibril, keep
    139          * the job and run it when event loop is running.
    140          */
    141         job_t *first_job = create_entry_configuration();
     214         * Create initial configuration while we are in a single fibril
     215         */
     216        int rc = create_entry_configuration();
     217        if (rc != EOK) {
     218                sysman_log(LVL_FATAL,
     219                    "Could not create initial configuration (%i).", rc);
     220                return rc;
     221        }
    142222
    143223        /*
     
    148228        fibril_add_ready(event_loop_fibril);
    149229
    150         /* Queue first job for processing */
    151         job_add_ref(first_job);
    152         sysman_object_observer(first_job, &first_job_handler, NULL);
    153         job_add_ref(first_job);
    154         sysman_raise_event(&sysman_event_job_process, first_job);
    155        
    156         /*
    157          * Releasing our own reference (could be merged with previous add_ref,
    158          * this is more explicit though.
    159          */
    160         job_del_ref(&first_job);
     230        /* Queue first job from sequence */
     231        prepare_and_run_job(&target_sequence[0]);
     232
     233        /* We're service too */
     234        rc = service_register(SERVICE_SYSMAN);
     235        if (rc != EOK) {
     236                sysman_log(LVL_FATAL,
     237                    "Cannot register at naming service (%i).", rc);
     238                return rc;
     239        }
    161240
    162241        /* Start sysman server */
  • uspace/srv/sysman/sysman.c

    r2dda1d4 r5559712  
    3535#include "log.h"
    3636#include "sysman.h"
     37#include "unit.h"
    3738
    3839
     
    150151
    151152                /* Process event */
    152                 sysman_log(LVL_DEBUG2, "process(%p, %p)", event->handler, event->data);
     153                sysman_log(LVL_DEBUG2, "process_event(%p, %p)",
     154                    event->handler, event->data);
    153155                event->handler(event->data);
    154156                free(event);
    155157        }
     158}
     159
     160/** Create and queue job for unit
     161 *
     162 * @param[in]  callback  callback must explicitly delete reference to job
     163 */
     164int sysman_queue_job(unit_t *unit, unit_state_t target_state,
     165    callback_handler_t callback, void *callback_arg)
     166{
     167        job_t *job = job_create(unit, target_state);
     168        if (job == NULL) {
     169                return ENOMEM;
     170        }
     171
     172        job_add_ref(job);
     173        sysman_object_observer(job, callback, callback_arg);
     174
     175        job_add_ref(job);
     176        sysman_raise_event(&sysman_event_job_process, job);
     177
     178        job_del_ref(&job);
     179        return EOK;
    156180}
    157181
     
    226250
    227251// NOTE must run in main event loop fibril
    228 void sysman_event_job_process(void *arg)
    229 {
    230         job_t *job = arg;
     252void sysman_event_job_process(void *data)
     253{
     254        job_t *job = data;
    231255        dyn_array_t job_closure;
    232256        dyn_array_initialize(&job_closure, job_ptr_t, 0);
     
    250274        job_del_ref(&job);
    251275
    252         // TODO explain why calling asynchronously
    253         sysman_raise_event(&sysman_event_job_queue_run, NULL);
     276        job_queue_process();
    254277        return;
    255278
     
    265288}
    266289
    267 
    268 void sysman_event_job_queue_run(void *unused)
    269 {
    270         job_t *job;
    271         while ((job = job_queue_pop_runnable())) {
    272                 job_run(job);
    273                 job_del_ref(&job);
    274         }
    275 }
    276 
    277 void sysman_event_job_changed(void *object)
    278 {
    279         notify_observers(object);
     290void sysman_event_job_finished(void *data)
     291{
     292        notify_observers(data);
    280293        /* Unreference the event data */
    281         job_t *job = object;
     294        job_t *job = data;
    282295        job_del_ref(&job);
    283 }
     296
     297        /* The finished job, might have been blocking */
     298        job_queue_process();
     299}
     300
     301void sysman_event_unit_exposee_created(void *data)
     302{
     303        unit_t *unit = data;
     304        unit_exposee_created(unit);
     305}
     306
     307void sysman_event_unit_failed(void *data)
     308{
     309        unit_t *unit = data;
     310        unit_fail(unit);
     311}
     312
     313void sysman_event_unit_state_changed(void *data)
     314{
     315        notify_observers(data);
     316}
  • uspace/srv/sysman/sysman.h

    r2dda1d4 r5559712  
    3737
    3838extern void sysman_events_init(void);
     39extern int sysman_events_loop(void *);
     40extern int sysman_queue_job(unit_t *, unit_state_t, callback_handler_t, void *);
    3941
    40 extern int sysman_events_loop(void *);
    4142
    4243extern void sysman_raise_event(event_handler_t, void *);
    43 
    4444extern int sysman_object_observer(void *, callback_handler_t, void *);
    4545
    4646
    4747extern void sysman_event_job_process(void *);
    48 extern void sysman_event_job_queue_run(void *);
    49 extern void sysman_event_job_changed(void *);
     48extern void sysman_event_job_finished(void *);
     49extern void sysman_event_unit_exposee_created(void *);
     50extern void sysman_event_unit_failed(void *);
     51extern void sysman_event_unit_state_changed(void *);
    5052
    5153#endif
  • uspace/srv/sysman/unit.c

    r2dda1d4 r5559712  
    3737#include <stdlib.h>
    3838#include <str.h>
     39#include <sysman/unit.h>
    3940
    4041#include "dep.h"
    4142#include "log.h"
     43#include "sysman.h"
    4244#include "unit.h"
    4345
    4446/** Virtual method table for each unit type */
    4547unit_vmt_t *unit_type_vmts[] = {
    46         [UNIT_TARGET]        = &unit_tgt_ops,
    47         [UNIT_MOUNT]         = &unit_mnt_ops,
    48         [UNIT_CONFIGURATION] = &unit_cfg_ops
     48        [UNIT_CONFIGURATION] = &unit_cfg_vmt,
     49        [UNIT_MOUNT]         = &unit_mnt_vmt,
     50        [UNIT_TARGET]        = &unit_tgt_vmt,
     51        [UNIT_SERVICE]       = &unit_svc_vmt
    4952};
    5053
     
    6164        assert(unit);
    6265
    63         // TODO is this necessary?
    64         memset(unit, 0, sizeof(unit_t));
     66        size_t size = unit_type_vmts[type]->size;
     67        memset(unit, 0, size);
    6568       
    6669        unit->type = type;
    67         unit->name = NULL;
    68 
    6970        unit->state = STATE_EMBRYO;
    7071
     
    103104}
    104105
    105 
    106 /** Issue request to restarter to start a unit
    107  *
    108  * Ideally this function is non-blocking synchronous, however, some units
    109  * cannot be started synchronously and thus return from this function generally
    110  * means that start was requested.
    111  *
    112  * Check state of the unit for actual result, start method can end in states:
    113  *   - STATE_STARTED, (succesful synchronous start)
    114  *   - STATE_STARTING, (succesful asynchronous start request)
    115  *   - STATE_FAILED.  (error occured)
    116  */
    117 int unit_start(unit_t *unit)
    118 {
    119         sysman_log(LVL_DEBUG, "%s('%s')", __func__, unit_name(unit));
    120         return UNIT_VMT(unit)->start(unit);
    121 }
    122 
    123106int unit_load(unit_t *unit, ini_configuration_t *ini_conf,
    124107    text_parse_t *text_parse)
     
    140123}
    141124
     125/** Issue request to restarter to start a unit
     126 *
     127 * Ideally this function is non-blocking synchronous, however, some units
     128 * cannot be started synchronously and thus return from this function generally
     129 * means that start was requested.
     130 *
     131 * Check state of the unit for actual result, start method can end in states:
     132 *   - STATE_STARTED, (succesful synchronous start)
     133 *   - STATE_STARTING, (succesful asynchronous start request)
     134 *   - STATE_FAILED.  (unit state changed and error occured)
     135 */
     136int unit_start(unit_t *unit)
     137{
     138        sysman_log(LVL_DEBUG, "%s('%s')", __func__, unit_name(unit));
     139        return UNIT_VMT(unit)->start(unit);
     140}
     141
     142void unit_exposee_created(unit_t *unit)
     143{
     144        sysman_log(LVL_DEBUG, "%s('%s')", __func__, unit_name(unit));
     145        return UNIT_VMT(unit)->exposee_created(unit);
     146}
     147
     148void unit_fail(unit_t *unit)
     149{
     150        sysman_log(LVL_DEBUG, "%s('%s')", __func__, unit_name(unit));
     151        return UNIT_VMT(unit)->fail(unit);
     152}
     153
     154void unit_notify_state(unit_t *unit)
     155{
     156        sysman_raise_event(&sysman_event_unit_state_changed, unit);
     157}
     158
    142159unit_type_t unit_type_name_to_type(const char *type_name)
    143160{
    144         if (str_cmp(type_name, "cfg") == 0)
     161        if (str_cmp(type_name, UNIT_CFG_TYPE_NAME) == 0)
    145162                return UNIT_CONFIGURATION;
    146163
    147         else if (str_cmp(type_name, "mnt") == 0)
     164        else if (str_cmp(type_name, UNIT_MNT_TYPE_NAME) == 0)
    148165                return UNIT_MOUNT;
    149166
    150         else if (str_cmp(type_name, "tgt") == 0)
     167        else if (str_cmp(type_name, UNIT_TGT_TYPE_NAME) == 0)
    151168                return UNIT_TARGET;
     169
     170        else if (str_cmp(type_name, UNIT_SVC_TYPE_NAME) == 0)
     171                return UNIT_SERVICE;
    152172
    153173        else
     
    160180        return unit->name ? unit->name : "";
    161181}
    162 
    163 
    164 
    165182
    166183bool unit_parse_unit_list(const char *value, void *dst, text_parse_t *parse,
  • uspace/srv/sysman/unit.h

    r2dda1d4 r5559712  
    4545        UNIT_MOUNT,
    4646        UNIT_CONFIGURATION,
     47        UNIT_SERVICE
    4748} unit_type_t;
    4849
     
    7374#include "unit_mnt.h"
    7475#include "unit_tgt.h"
     76#include "unit_svc.h"
    7577
    76 #define DEFINE_CAST(NAME, TYPE, ENUM_TYPE)                           \
    77         static inline TYPE *CAST_##NAME(unit_t *u)                   \
    78         {                                                            \
    79                 if (u->type == ENUM_TYPE)                            \
    80                         return (TYPE *)u;                            \
    81                 else                                                 \
    82                         return NULL;                                 \
    83         }                                                            \
     78#define DEFINE_CAST(NAME, TYPE, ENUM_TYPE)                                     \
     79        static inline TYPE *CAST_##NAME(unit_t *u)                             \
     80        {                                                                      \
     81                if (u->type == ENUM_TYPE)                                      \
     82                        return (TYPE *)u;                                      \
     83                else                                                           \
     84                        return NULL;                                           \
     85        }                                                                      \
    8486
    8587DEFINE_CAST(CFG, unit_cfg_t, UNIT_CONFIGURATION)
    8688DEFINE_CAST(MNT, unit_mnt_t, UNIT_MOUNT)
    8789DEFINE_CAST(TGT, unit_tgt_t, UNIT_TARGET)
     90DEFINE_CAST(SVC, unit_svc_t, UNIT_SERVICE)
    8891
    8992struct unit_vmt {
     
    97100
    98101        int (*start)(unit_t *);
     102
     103        void (*exposee_created)(unit_t *);
     104
     105        void (*fail)(unit_t *);
    99106};
    100107
    101108extern unit_vmt_t *unit_type_vmts[];
    102109
    103 #define DEFINE_UNIT_VMT(PREFIX)                                      \
    104         unit_vmt_t PREFIX##_ops = {                                  \
    105                 .size    = sizeof(PREFIX##_t),                       \
    106                 .init    = &PREFIX##_init,                           \
    107                 .load    = &PREFIX##_load,                           \
    108                 .destroy = &PREFIX##_destroy,                        \
    109                 .start   = &PREFIX##_start                           \
     110#define DEFINE_UNIT_VMT(PREFIX)                                                \
     111        unit_vmt_t PREFIX##_vmt = {                                            \
     112                .size            = sizeof(PREFIX##_t),                         \
     113                .init            = &PREFIX##_init,                             \
     114                .load            = &PREFIX##_load,                             \
     115                .destroy         = &PREFIX##_destroy,                          \
     116                .start           = &PREFIX##_start,                            \
     117                .exposee_created = &PREFIX##_exposee_created,                  \
     118                .fail            = &PREFIX##_fail                              \
    110119        };
    111120
     
    115124extern void unit_destroy(unit_t **);
    116125
    117 // TODO add flags argument with explicit notification?
    118 extern void unit_set_state(unit_t *, unit_state_t);
    119 
    120126extern int unit_load(unit_t *, ini_configuration_t *, text_parse_t *);
    121127extern int unit_start(unit_t *);
     128extern void unit_exposee_created(unit_t *);
     129extern void unit_fail(unit_t *);
     130
     131extern void unit_notify_state(unit_t *);
    122132
    123133extern unit_type_t unit_type_name_to_type(const char *);
  • uspace/srv/sysman/units/unit_cfg.c

    r2dda1d4 r5559712  
    3636#include <stdlib.h>
    3737#include <str.h>
     38#include <sysman/unit.h>
    3839
    3940#include "configuration.h"
     
    6667        text_parse_init(&text_parse);
    6768
    68         const char *last_dot = str_rchr(filename, '.');
    69         if (last_dot == NULL) {
     69        const char *last_sep = str_rchr(filename, UNIT_NAME_SEPARATOR);
     70        if (last_sep == NULL) {
    7071                rc = EINVAL;
    7172                goto finish;
     
    7374
    7475        const char *unit_name = filename;
    75         const char *unit_type_name = last_dot + 1;
     76        const char *unit_type_name = last_sep + 1;
    7677
    7778        unit_type_t unit_type = unit_type_name_to_type(unit_type_name);
     
    195196        unit_cfg_t *u_cfg = CAST_CFG(unit);
    196197        assert(u_cfg);
    197 
    198         u_cfg->path = NULL;
    199 }
    200 
    201 
     198}
    202199
    203200static void unit_cfg_destroy(unit_t *unit)
     
    243240}
    244241
     242static void unit_cfg_exposee_created(unit_t *unit)
     243{
     244        /* Configuration has no exposees. */
     245        assert(false);
     246}
     247
     248static void unit_cfg_fail(unit_t *unit)
     249{
     250        /* Configuration cannot async fail. */
     251        assert(false);
     252}
     253
    245254DEFINE_UNIT_VMT(unit_cfg)
    246255
  • uspace/srv/sysman/units/unit_cfg.h

    r2dda1d4 r5559712  
    3838} unit_cfg_t;
    3939
    40 extern unit_vmt_t unit_cfg_ops;
     40extern unit_vmt_t unit_cfg_vmt;
    4141
    4242#endif
  • uspace/srv/sysman/units/unit_mnt.c

    r2dda1d4 r5559712  
    3232#include <stdlib.h>
    3333#include <vfs/vfs.h>
     34#include <str.h>
    3435
    3536#include "log.h"
     37#include "sysman.h"
    3638#include "unit.h"
    3739
     
    3941
    4042static config_item_t unit_configuration[] = {
    41         {"What",  &config_parse_string, offsetof(unit_mnt_t, device),     NULL},
    42         {"Where", &config_parse_string, offsetof(unit_mnt_t, mountpoint), NULL},
    43         {"Type",  &config_parse_string, offsetof(unit_mnt_t, type),       NULL},
     43        {"What",      &config_parse_string, offsetof(unit_mnt_t, device),     NULL},
     44        {"Where",     &config_parse_string, offsetof(unit_mnt_t, mountpoint), NULL},
     45        {"Type",      &config_parse_string, offsetof(unit_mnt_t, type),       NULL},
     46        {"Autostart", &config_parse_bool,   offsetof(unit_mnt_t, autostart),  "true"},
     47        {"Blocking",  &config_parse_bool,   offsetof(unit_mnt_t, blocking),   "true"},
    4448        CONFIGURATION_ITEM_SENTINEL
    4549};
    4650
     51typedef struct {
     52        char *type;
     53        char *mountpoint;
     54        char *device;
     55        char *options;
     56        unsigned int flags;
     57        unsigned int instance;
     58
     59        unit_t *unit;
     60        bool owner;
     61} mount_data_t;
     62
     63static void mount_data_destroy(mount_data_t **mnt_data_ptr)
     64{
     65        assert(mnt_data_ptr);
     66        if (*mnt_data_ptr == NULL) {
     67                return;
     68        }
     69
     70        mount_data_t *mnt_data = *mnt_data_ptr;
     71        free(mnt_data->type);
     72        free(mnt_data->mountpoint);
     73        free(mnt_data->device);
     74        free(mnt_data->options);
     75
     76        free(mnt_data);
     77        *mnt_data_ptr = NULL;
     78}
     79
     80static bool mount_data_copy(mount_data_t *src, mount_data_t **dst_ptr)
     81{
     82        mount_data_t *dst = malloc(sizeof(mount_data_t));
     83        if (dst == NULL) {
     84                goto fail;
     85        }
     86
     87        dst->type = str_dup(src->type);
     88        if (dst->type == NULL)
     89                goto fail;
     90
     91        dst->mountpoint = str_dup(src->mountpoint);
     92        if (dst->mountpoint == NULL)
     93                goto fail;
     94
     95        dst->device = str_dup(src->device);
     96        if (dst->device == NULL)
     97                goto fail;
     98
     99        dst->options = src->options ? str_dup(src->options) : NULL;
     100        if (src->options != NULL && dst->options == NULL)
     101                goto fail;
     102
     103        dst->flags = src->flags;
     104        dst->instance = src->instance;
     105        dst->unit = src->unit;
     106        dst->owner = true;
     107
     108        *dst_ptr = dst;
     109        return true;
     110
     111fail:
     112        mount_data_destroy(&dst);
     113        return false;
     114}
     115
    47116static void unit_mnt_init(unit_t *unit)
    48117{
    49118        unit_mnt_t *u_mnt = CAST_MNT(unit);
    50119        assert(u_mnt);
    51 
    52         u_mnt->type = NULL;
    53         u_mnt->mountpoint = NULL;
    54         u_mnt->device = NULL;
    55120}
    56121
     
    60125        unit_mnt_t *u_mnt = CAST_MNT(unit);
    61126
    62         sysman_log(LVL_DEBUG2, "%s, %p, %p, %p", __func__,
    63             u_mnt->type, u_mnt->mountpoint, u_mnt->device);
    64127        free(u_mnt->type);
    65128        free(u_mnt->mountpoint);
     
    85148}
    86149
     150static int mount_exec(void *arg)
     151{
     152        mount_data_t *mnt_data = arg;
     153        /*sysman_log(LVL_DEBUG2, "%s(%p, %p, %p, %p, %x, %u)",
     154            __func__,
     155            mnt_data->type, mnt_data->mountpoint, mnt_data->device, mnt_data->options,
     156            mnt_data->flags, mnt_data->instance);*/
     157        int rc = mount(mnt_data->type, mnt_data->mountpoint, mnt_data->device,
     158            mnt_data->options ? mnt_data->options : "",
     159            mnt_data->flags, mnt_data->instance);
     160
     161        if (rc == EOK) {
     162                sysman_log(LVL_DEBUG, "Mount ('%s') mounted",
     163                    unit_name(mnt_data->unit));
     164                /*
     165                 * Emulate future VFS broker fibril that notifies about created
     166                 * exposee.
     167                 * Difference: It'll notify exposee name only, we'll have to
     168                 * match it...
     169                 */
     170                sysman_raise_event(&sysman_event_unit_exposee_created,
     171                    mnt_data->unit);
     172        } else {
     173                sysman_log(LVL_ERROR, "Mount ('%s') failed (%i)",
     174                    unit_name(mnt_data->unit), rc);
     175                /*
     176                 * Think about analogy of this event, probably timeout or sthing
     177                 */
     178                sysman_raise_event(&sysman_event_unit_failed,
     179                    mnt_data->unit);
     180        }
     181
     182        if (mnt_data->owner) {
     183                mount_data_destroy(&mnt_data);
     184        }
     185
     186        return EOK;
     187}
     188
    87189static int unit_mnt_start(unit_t *unit)
    88190{
    89         // TODO replace with non-blocking
    90         const bool blocking = true;
    91191        unit_mnt_t *u_mnt = CAST_MNT(unit);
    92192        assert(u_mnt);
     193        /* autostart implies blocking */
     194        assert(!u_mnt->autostart || u_mnt->blocking);
    93195
    94196       
     
    96198        assert(unit->state == STATE_STOPPED);
    97199
    98 
    99         // TODO use other mount parameters
    100         int rc = mount(u_mnt->type, u_mnt->mountpoint, u_mnt->device, "",
    101             blocking ? IPC_FLAG_BLOCKING : 0, 0);
    102 
    103         if (blocking) {
    104                 if (rc == EOK) {
    105                         sysman_log(LVL_DEBUG, "Mount ('%s') mounted", unit_name(unit));
    106                         unit->state = STATE_STARTED;
    107                 } else {
    108                         sysman_log(LVL_ERROR, "Mount ('%s') failed (%i)",
    109                             unit_name(unit), rc);
    110                         unit->state = STATE_FAILED;
     200        mount_data_t mnt_data;
     201        memset(&mnt_data, 0, sizeof(mnt_data));
     202        mnt_data.type       = u_mnt->type;
     203        mnt_data.mountpoint = u_mnt->mountpoint;
     204        mnt_data.device     = u_mnt->device;
     205        /* TODO use other mount parameters
     206         * mnt_data.options    = u_mnt->options;
     207         * mnt_data.instance   = u_mnt->instance;
     208         */
     209
     210        mnt_data.flags |= u_mnt->blocking ? IPC_FLAG_BLOCKING : 0;
     211        mnt_data.flags |= u_mnt->autostart ? IPC_FLAG_AUTOSTART : 0;
     212        mnt_data.unit = unit;
     213
     214        if (u_mnt->blocking) {
     215                mount_data_t *heap_mnt_data = NULL;
     216                if (!mount_data_copy(&mnt_data, &heap_mnt_data)) {
     217                        return ENOMEM;
    111218                }
     219                fid_t fib = fibril_create(&mount_exec, heap_mnt_data);
     220                unit->state = STATE_STARTING;
     221                fibril_add_ready(fib);
    112222        } else {
    113                 if (rc == EOK) {
    114                         sysman_log(LVL_DEBUG, "Mount ('%s') requested", unit_name(unit));
    115                         unit->state = STATE_STARTING;
    116                 } else {
    117                         sysman_log(LVL_ERROR, "Mount ('%s') request failed (%i)",
    118                             unit_name(unit), rc);
    119                         unit->state = STATE_FAILED;
    120                 }
    121         }
    122 
    123         return rc;
    124 }
     223                unit->state = STATE_STARTING;
     224                mount_exec(&mnt_data);
     225        }
     226
     227        return EOK;
     228}
     229
     230static void unit_mnt_exposee_created(unit_t *unit)
     231{
     232        assert(CAST_MNT(unit));
     233        assert(unit->state == STATE_STOPPED || unit->state == STATE_STARTING);
     234
     235        unit->state = STATE_STARTED;
     236        unit_notify_state(unit);
     237}
     238
     239static void unit_mnt_fail(unit_t *unit)
     240{
     241        assert(CAST_MNT(unit));
     242        assert(unit->state == STATE_STARTING);
     243
     244        unit->state = STATE_FAILED;
     245        unit_notify_state(unit);
     246}
     247
    125248
    126249DEFINE_UNIT_VMT(unit_mnt)
  • uspace/srv/sysman/units/unit_mnt.h

    r2dda1d4 r5559712  
    3838        char *mountpoint;
    3939        char *device;
     40
     41        /** Should be underlying units (FS server, device) be autostarted */
     42        bool autostart;
     43
     44        /** Should mount call be blocking */
     45        bool blocking;
    4046} unit_mnt_t;
    4147
    42 extern unit_vmt_t unit_mnt_ops;
     48extern unit_vmt_t unit_mnt_vmt;
    4349
    4450#endif
  • uspace/srv/sysman/units/unit_tgt.c

    r2dda1d4 r5559712  
    6363}
    6464
     65static void unit_tgt_exposee_created(unit_t *unit)
     66{
     67        /* Target has no exposees. */
     68        assert(false);
     69}
     70
     71static void unit_tgt_fail(unit_t *unit)
     72{
     73        // TODO define semantics and implement
     74}
     75
     76
    6577DEFINE_UNIT_VMT(unit_tgt)
    6678
  • uspace/srv/sysman/units/unit_tgt.h

    r2dda1d4 r5559712  
    3636} unit_tgt_t;
    3737
    38 extern unit_vmt_t unit_tgt_ops;
     38extern unit_vmt_t unit_tgt_vmt;
    3939
    4040#endif
Note: See TracChangeset for help on using the changeset viewer.