| 2949 | } |
| 2950 | |
| 2951 | cbm_daemon_application_t *cbm_daemon_application_new( |
| 2952 | const cbm_daemon_application_config_t *config) { |
| 2953 | cbm_daemon_application_t *application = calloc(1, sizeof(*application)); |
| 2954 | if (!application) { |
| 2955 | return NULL; |
| 2956 | } |
| 2957 | cbm_mutex_init(&application->mutex); |
| 2958 | application->physical_job_limit = APPLICATION_DEFAULT_PHYSICAL_JOB_LIMIT; |
| 2959 | size_t aggregate_memory_budget_bytes = cbm_mem_budget(); |
| 2960 | if (config) { |
| 2961 | if ((config->ui_readiness_secret != NULL || config->ui_readiness_secret_length != 0) && |
| 2962 | (!config->ui_readiness_secret || |
| 2963 | config->ui_readiness_secret_length != sizeof(application->ui_readiness_secret))) { |
| 2964 | cbm_mutex_destroy(&application->mutex); |
| 2965 | cbm_secure_zero(application->ui_readiness_secret, |
| 2966 | sizeof(application->ui_readiness_secret)); |
| 2967 | free(application); |
| 2968 | return NULL; |
| 2969 | } |
| 2970 | application->watcher = config->watcher; |
| 2971 | application->config = config->config; |
| 2972 | application->project_locks = config->project_locks; |
| 2973 | if (config->physical_job_limit > 0) { |
| 2974 | application->physical_job_limit = config->physical_job_limit; |
| 2975 | } |
| 2976 | if (config->aggregate_memory_budget_bytes > 0) { |
| 2977 | aggregate_memory_budget_bytes = config->aggregate_memory_budget_bytes; |
| 2978 | } |
| 2979 | if (config->worker_ops) { |
| 2980 | application->worker_ops = *config->worker_ops; |
| 2981 | } |
| 2982 | if (config->update_ops) { |
| 2983 | application->update_ops = *config->update_ops; |
| 2984 | } |
| 2985 | if (config->ui_readiness_secret && |
| 2986 | config->ui_readiness_secret_length == sizeof(application->ui_readiness_secret)) { |
| 2987 | memcpy(application->ui_readiness_secret, config->ui_readiness_secret, |
| 2988 | sizeof(application->ui_readiness_secret)); |
| 2989 | application->ui_readiness_secret_set = true; |
| 2990 | } |
| 2991 | } |
| 2992 | /* The per-worker slice is decided at spawn time (see |
| 2993 | * application_worker_memory_slice_locked): the aggregate divided by the |
| 2994 | * jobs active then, so a lone worker may use the whole aggregate and |
| 2995 | * concurrent jobs split it (decision 2, #1997 #832) — the former fixed |
| 2996 | * aggregate/limit slice starved a lone job on hosts like #1864. The absurd |
| 2997 | * sub-byte-per-slot case is still made safe by reducing effective capacity |
| 2998 | * so every admitted job can receive at least one byte; normal daemon |
| 2999 | * budgets are many orders larger. */ |
| 3000 | if (aggregate_memory_budget_bytes > 0 && |
| 3001 | application->physical_job_limit > aggregate_memory_budget_bytes) { |
| 3002 | application->physical_job_limit = aggregate_memory_budget_bytes; |
| 3003 | } |
| 3004 | application->aggregate_memory_budget_bytes = aggregate_memory_budget_bytes; |
| 3005 | if (!application->worker_ops.start) { |
| 3006 | application->worker_ops = (cbm_daemon_application_worker_ops_t){ |
| 3007 | .context = NULL, |
| 3008 | .start = application_worker_start_default, |