1.1 --- a/libexec/include/exec/elf.h Fri Apr 07 23:34:59 2023 +0200
1.2 +++ b/libexec/include/exec/elf.h Fri Apr 07 23:35:21 2023 +0200
1.3 @@ -66,6 +66,7 @@
1.4 protected:
1.5 HEADER *_header;
1.6 Segment **_segments = NULL;
1.7 + unsigned int _nsegments;
1.8
1.9 public:
1.10 explicit PayloadVariant(HEADER *header);
2.1 --- a/libexec/include/exec/process_creating.h Fri Apr 07 23:34:59 2023 +0200
2.2 +++ b/libexec/include/exec/process_creating.h Fri Apr 07 23:35:21 2023 +0200
2.3 @@ -76,8 +76,6 @@
2.4
2.5 long init_external_pager(l4_cap_idx_t *pager);
2.6
2.7 - long init_process_monitor(l4_cap_idx_t *monitor);
2.8 -
2.9 long configure_task();
2.10
2.11 long allocate_internal_pager();
2.12 @@ -90,10 +88,14 @@
2.13
2.14 long start_program(l4_cap_idx_t monitor, int argc, const char *argv[]);
2.15
2.16 + long _start(int argc, const char *argv[], l4_cap_idx_t process);
2.17 +
2.18 public:
2.19 explicit ProcessCreating(const char *rm_filename, file_t *rm_file);
2.20
2.21 - virtual long start(int argc, const char *argv[], l4_cap_idx_t *process);
2.22 + virtual long init_process_monitor(l4_cap_idx_t *monitor);
2.23 +
2.24 + virtual long start(int argc, const char *argv[], l4_cap_idx_t process);
2.25 };
2.26
2.27 /* vim: tabstop=2 expandtab shiftwidth=2
3.1 --- a/libexec/include/exec/process_creator_resource.h Fri Apr 07 23:34:59 2023 +0200
3.2 +++ b/libexec/include/exec/process_creator_resource.h Fri Apr 07 23:35:21 2023 +0200
3.3 @@ -47,9 +47,11 @@
3.4 void *interface()
3.5 { return static_cast<Opener *>(this); }
3.6
3.7 - /* Process creator interface methods. */
3.8 + /* Local operations. */
3.9
3.10 - virtual long start(int argc, const char *argv[], l4_cap_idx_t *process);
3.11 + virtual long init_process(l4_cap_idx_t *process);
3.12 +
3.13 + virtual long start(int argc, const char *argv[], l4_cap_idx_t process);
3.14
3.15 /* Opener interface methods. */
3.16
4.1 --- a/libexec/lib/src/elf.cc Fri Apr 07 23:34:59 2023 +0200
4.2 +++ b/libexec/lib/src/elf.cc Fri Apr 07 23:35:21 2023 +0200
4.3 @@ -100,6 +100,11 @@
4.4 PayloadVariant<HEADER, PROGRAM_HEADER>::PayloadVariant(HEADER *header)
4.5 : _header(header)
4.6 {
4.7 + /* Record the number of segments since various methods depend on it, but the
4.8 + header data may be unavailable when it is used, upon destruction, for
4.9 + example. */
4.10 +
4.11 + _nsegments = _header->e_phnum;
4.12 }
4.13
4.14 /* Specific payload destruction. */
4.15 @@ -111,6 +116,8 @@
4.16 {
4.17 for (unsigned int i = 0; i < segments(); i++)
4.18 delete _segments[i];
4.19 +
4.20 + delete _segments;
4.21 }
4.22 }
4.23
4.24 @@ -135,7 +142,7 @@
4.25 template <typename HEADER, typename PROGRAM_HEADER>
4.26 unsigned int PayloadVariant<HEADER, PROGRAM_HEADER>::segments()
4.27 {
4.28 - return _header->e_phnum;
4.29 + return _nsegments;
4.30 }
4.31
4.32 template <typename HEADER, typename PROGRAM_HEADER>
5.1 --- a/libexec/lib/src/process_creating.cc Fri Apr 07 23:34:59 2023 +0200
5.2 +++ b/libexec/lib/src/process_creating.cc Fri Apr 07 23:35:21 2023 +0200
5.3 @@ -86,6 +86,7 @@
5.4 long ProcessCreating::init_external_pager(l4_cap_idx_t *pager)
5.5 {
5.6 _exec_pager = new ExternalPager(0, 10 * L4_PAGESIZE);
5.7 + _exec_pager->set_monitor(_monitor);
5.8
5.9 /* Initialise pager regions for the region mapper. */
5.10
5.11 @@ -119,13 +120,7 @@
5.12
5.13 /* Start the monitor in a separate thread. */
5.14
5.15 - long err = ResourceServer(_monitor).start_thread(monitor);
5.16 -
5.17 - if (err)
5.18 - return err;
5.19 -
5.20 - _exec_pager->set_monitor(_monitor);
5.21 - return L4_EOK;
5.22 + return ResourceServer(_monitor).start_thread(monitor);
5.23 }
5.24
5.25 /* Configure the environment for the task. */
5.26 @@ -369,10 +364,8 @@
5.27 program arguments, returning a reference to the process monitor as an object
5.28 for interacting with the process. */
5.29
5.30 -long ProcessCreating::start(int argc, const char *argv[], l4_cap_idx_t *process)
5.31 +long ProcessCreating::_start(int argc, const char *argv[], l4_cap_idx_t process)
5.32 {
5.33 - std::lock_guard<std::mutex> guard(_lock);
5.34 -
5.35 /* Open the program file, handling any error conditions. If successfully
5.36 opened, it will be closed when the process terminates. */
5.37
5.38 @@ -405,10 +398,6 @@
5.39 if (err)
5.40 return err;
5.41
5.42 - err = init_process_monitor(process);
5.43 - if (err)
5.44 - return err;
5.45 -
5.46 err = configure_task();
5.47 if (err)
5.48 return err;
5.49 @@ -421,7 +410,7 @@
5.50 if (err)
5.51 return err;
5.52
5.53 - err = start_program(*process, argc, argv);
5.54 + err = start_program(process, argc, argv);
5.55 if (err)
5.56 return err;
5.57
5.58 @@ -444,5 +433,21 @@
5.59 return L4_EOK;
5.60 }
5.61
5.62 +/* Start the given program, notifying the process monitor upon any error. */
5.63 +
5.64 +long ProcessCreating::start(int argc, const char *argv[], l4_cap_idx_t process)
5.65 +{
5.66 + std::lock_guard<std::mutex> guard(_lock);
5.67 +
5.68 + long err = _start(argc, argv, process);
5.69 +
5.70 + /* Communicate the error using the signal value. */
5.71 +
5.72 + if (err)
5.73 + _monitor->notify_all(NOTIFY_TASK_ERROR, (notify_values_t) {0, err});
5.74 +
5.75 + return err;
5.76 +}
5.77 +
5.78 /* vim: tabstop=2 expandtab shiftwidth=2
5.79 */
6.1 --- a/libexec/lib/src/process_creator_context_resource.cc Fri Apr 07 23:34:59 2023 +0200
6.2 +++ b/libexec/lib/src/process_creator_context_resource.cc Fri Apr 07 23:35:21 2023 +0200
6.3 @@ -67,9 +67,27 @@
6.4 printf("argv[%d] = %s\n", i, argv[i]);
6.5 }
6.6
6.7 - /* Start the new process, obtaining a reference to it. */
6.8 + /* Obtain a reference to a new process and send the reference to the client.
6.9 + This must be done in advance of actually starting the program since the
6.10 + program may complete before the client gets the reference. */
6.11 +
6.12 + long err = _creator->init_process(process);
6.13 +
6.14 + if (!err)
6.15 + err = complete_ProcessCreatorContext_start(*process);
6.16 +
6.17 + /* Attempt to communicate any error from these activities. */
6.18
6.19 - return _creator->start(argc, argv, process);
6.20 + if (err)
6.21 + return err;
6.22 +
6.23 + /* Attempt to actually start the process. Errors cannot be communicated as a
6.24 + reply, so a notification is sent via the process monitor instead by the
6.25 + process creator. */
6.26 +
6.27 + _creator->start(argc, argv, *process);
6.28 +
6.29 + return IPC_MESSAGE_SENT;
6.30 }
6.31
6.32 /* vim: tabstop=4 expandtab shiftwidth=4
7.1 --- a/libexec/lib/src/process_creator_resource.cc Fri Apr 07 23:34:59 2023 +0200
7.2 +++ b/libexec/lib/src/process_creator_resource.cc Fri Apr 07 23:35:21 2023 +0200
7.3 @@ -48,9 +48,14 @@
7.4
7.5 /* ProcessCreator interface methods. */
7.6
7.7 +long ProcessCreatorResource::init_process(l4_cap_idx_t *process)
7.8 +{
7.9 + return _creating.init_process_monitor(process);
7.10 +}
7.11 +
7.12 /* Start the new process, obtaining a reference to it. */
7.13
7.14 -long ProcessCreatorResource::start(int argc, const char *argv[], l4_cap_idx_t *process)
7.15 +long ProcessCreatorResource::start(int argc, const char *argv[], l4_cap_idx_t process)
7.16 {
7.17 return _creating.start(argc, argv, process);
7.18 }
8.1 --- a/libfsclient/include/fsclient/process.h Fri Apr 07 23:34:59 2023 +0200
8.2 +++ b/libfsclient/include/fsclient/process.h Fri Apr 07 23:35:21 2023 +0200
8.3 @@ -58,8 +58,9 @@
8.4
8.5 process_t *process_new();
8.6 void process_close(process_t *process);
8.7 +long process_error(process_t *process);
8.8 void process_init(process_t *process);
8.9 -long process_start(process_t *process, int argc, char *argv[]);
8.10 +long process_start(process_t *process, int argc, const char *argv[]);
8.11
8.12 /* Notification support. */
8.13
9.1 --- a/libfsclient/lib/src/file.cc Fri Apr 07 23:34:59 2023 +0200
9.2 +++ b/libfsclient/lib/src/file.cc Fri Apr 07 23:35:21 2023 +0200
9.3 @@ -95,7 +95,9 @@
9.4 /* Initialise the notifiable section of the structure. */
9.5
9.6 file->notifiable.notifications = 0;
9.7 + file->notifiable.pending_notifications = 0;
9.8 file->notifiable.base = (notifiable_base_t *) file;
9.9 + file->notifiable.handler = NULL;
9.10 }
9.11
9.12
9.13 @@ -634,7 +636,6 @@
9.14
9.15 void file_notify_close(file_notifier_t *notifier)
9.16 {
9.17 - notifier->obj->stop();
9.18 delete notifier->obj;
9.19 delete notifier;
9.20 }
9.21 @@ -677,8 +678,7 @@
9.22
9.23 long file_notify_wait_file(file_t *file, file_notifier_t *notifier)
9.24 {
9.25 - SpecificObjectNotifier *specific_notifier = dynamic_cast<SpecificObjectNotifier *>(notifier->obj);
9.26 - long err = specific_notifier->wait_object(file_notifiable(file));
9.27 + long err = notifier->obj->wait_object(file_notifiable(file));
9.28
9.29 /* Unsubscribe if a closure notification has been received. */
9.30
9.31 @@ -692,9 +692,8 @@
9.32
9.33 long file_notify_wait_files(file_t **file, file_notifier_t *notifier)
9.34 {
9.35 - GeneralObjectNotifier *general_notifier = dynamic_cast<GeneralObjectNotifier *>(notifier->obj);
9.36 notifiable_t *notifiable;
9.37 - long err = general_notifier->wait(¬ifiable);
9.38 + long err = notifier->obj->wait(¬ifiable);
9.39
9.40 *file = (file_t *) notifiable->base;
9.41
10.1 --- a/libfsclient/lib/src/process.cc Fri Apr 07 23:34:59 2023 +0200
10.2 +++ b/libfsclient/lib/src/process.cc Fri Apr 07 23:35:21 2023 +0200
10.3 @@ -34,6 +34,17 @@
10.4
10.5
10.6
10.7 +/* Utility functions. */
10.8 +
10.9 +static bool _process_terminated(process_t *process)
10.10 +{
10.11 + return ((process->notifiable.notifications & NOTIFY_TASK_SIGNAL) &&
10.12 + (process->notifiable.values.sig == 0)) ||
10.13 + (process->notifiable.notifications & NOTIFY_TASK_ERROR);
10.14 +}
10.15 +
10.16 +
10.17 +
10.18 /* Create a new process object. */
10.19
10.20 process_t *process_new()
10.21 @@ -60,17 +71,34 @@
10.22 process_init(process);
10.23 }
10.24
10.25 +/* Return any process initiation error. */
10.26 +
10.27 +long process_error(process_t *process)
10.28 +{
10.29 + if (process->notifiable.notifications & NOTIFY_TASK_ALL)
10.30 + return process->notifiable.values.val;
10.31 + else
10.32 + return L4_EOK;
10.33 +}
10.34 +
10.35 /* Initialise the given process structure. */
10.36
10.37 void process_init(process_t *process)
10.38 {
10.39 process->ref = L4_INVALID_CAP;
10.40 +
10.41 + /* Initialise the notifiable section of the structure. */
10.42 +
10.43 + process->notifiable.notifications = 0;
10.44 + process->notifiable.pending_notifications = 0;
10.45 + process->notifiable.base = (notifiable_base_t *) process;
10.46 + process->notifiable.handler = NULL;
10.47 }
10.48
10.49 /* Start a process using the given arguments.
10.50 NOTE: This does not yet obtain input/output pipes. */
10.51
10.52 -long process_start(process_t *process, int argc, char *argv[])
10.53 +long process_start(process_t *process, int argc, const char *argv[])
10.54 {
10.55 l4_cap_idx_t server = l4re_env_get_cap(ENV_PROCESS_SERVER_NAME);
10.56
10.57 @@ -106,6 +134,7 @@
10.58 /* Initialise the notifiable section of the structure. */
10.59
10.60 process->notifiable.notifications = 0;
10.61 + process->notifiable.pending_notifications = 0;
10.62 process->notifiable.base = (notifiable_base_t *) process;
10.63
10.64 /* Close the context, although a separate mechanism could permit contexts to
10.65 @@ -152,7 +181,6 @@
10.66
10.67 void process_notify_close(process_notifier_t *notifier)
10.68 {
10.69 - notifier->obj->stop();
10.70 delete notifier->obj;
10.71 delete notifier;
10.72 }
10.73 @@ -195,17 +223,12 @@
10.74
10.75 long process_notify_wait_process(process_t *process, process_notifier_t *notifier)
10.76 {
10.77 - SpecificObjectNotifier *specific_notifier = dynamic_cast<SpecificObjectNotifier *>(notifier->obj);
10.78 - long err = specific_notifier->wait_object(process_notifiable(process));
10.79 + long err = notifier->obj->wait_object(process_notifiable(process));
10.80
10.81 /* Unsubscribe if a termination notification has been received. */
10.82
10.83 - if (!err && (process->notifiable.notifications & NOTIFY_TASK_SIGNAL) &&
10.84 - (process->notifiable.values.sig == 0))
10.85 - {
10.86 + if (!err && _process_terminated(process))
10.87 process_notify_unsubscribe(process, notifier);
10.88 - process_close(process);
10.89 - }
10.90
10.91 return err;
10.92 }
10.93 @@ -214,20 +237,15 @@
10.94
10.95 long process_notify_wait_processes(process_t **process, process_notifier_t *notifier)
10.96 {
10.97 - GeneralObjectNotifier *general_notifier = dynamic_cast<GeneralObjectNotifier *>(notifier->obj);
10.98 notifiable_t *notifiable;
10.99 - long err = general_notifier->wait(¬ifiable);
10.100 + long err = notifier->obj->wait(¬ifiable);
10.101
10.102 *process = (process_t *) notifiable->base;
10.103
10.104 /* Unsubscribe if a termination notification has been received. */
10.105
10.106 - if (!err && ((*process)->notifiable.notifications & NOTIFY_TASK_SIGNAL) &&
10.107 - ((*process)->notifiable.values.sig == 0))
10.108 - {
10.109 + if (!err && _process_terminated(*process))
10.110 process_notify_unsubscribe(*process, notifier);
10.111 - process_close(*process);
10.112 - }
10.113
10.114 return err;
10.115 }
11.1 --- a/libnotifier/include/notifier/notifier.h Fri Apr 07 23:34:59 2023 +0200
11.2 +++ b/libnotifier/include/notifier/notifier.h Fri Apr 07 23:35:21 2023 +0200
11.3 @@ -23,8 +23,8 @@
11.4
11.5 #include <condition_variable>
11.6 #include <list>
11.7 -#include <map>
11.8 #include <mutex>
11.9 +#include <set>
11.10 #include <vector>
11.11
11.12 #include <resource/resource.h>
11.13 @@ -34,36 +34,10 @@
11.14
11.15
11.16
11.17 -/* Object-specific notification details. */
11.18 -
11.19 -class ObjectNotificationState
11.20 -{
11.21 -public:
11.22 - /* Synchronisation primitives for state access and notification. */
11.23 -
11.24 - std::mutex lock;
11.25 - std::condition_variable condition;
11.26 -
11.27 - /* Pending notifications for monitored objects. */
11.28 -
11.29 - notify_flags_t pending_notifications = 0;
11.30 - notify_values_t pending_values = NOTIFY_VALUES_NULL;
11.31 -
11.32 - /* Endpoints associated with monitored objects. */
11.33 -
11.34 - l4_cap_idx_t endpoint = L4_INVALID_CAP;
11.35 -
11.36 - bool is_null() { return l4_is_invalid_cap(endpoint); }
11.37 -};
11.38 -
11.39 -
11.40 -
11.41 /* Collection types. */
11.42
11.43 -typedef std::map<notifiable_t *, ObjectNotificationState> ObjectNotificationStates;
11.44 -typedef std::map<notifiable_t *, std::mutex> ObjectStateLocks;
11.45 -
11.46 -typedef std::vector<ipc_server_config_type *> ServerConfigs;
11.47 +typedef std::list<notifiable_t *> NotifiableObjectQueue;
11.48 +typedef std::set<notifiable_t *> NotifiableObjects;
11.49
11.50
11.51
11.52 @@ -72,102 +46,43 @@
11.53 class ObjectNotifier
11.54 {
11.55 protected:
11.56 - /* General state access locking. */
11.57 -
11.58 - std::mutex _state_lock;
11.59 -
11.60 - /* Object-specific state locking. */
11.61 + /* Locking for the affected queue and monitored object registry. */
11.62
11.63 - ObjectStateLocks _object_locks;
11.64 -
11.65 - /* Notification state. */
11.66 -
11.67 - ObjectNotificationStates _state;
11.68 + std::mutex _affected_lock, _monitored_lock;
11.69 + std::condition_variable _condition;
11.70
11.71 - /* Notifier resource details. */
11.72 -
11.73 - ServerConfigs _configs;
11.74 - bool _started = false;
11.75 - l4_cap_idx_t _irq = L4_INVALID_CAP;
11.76 + /* Objects affected by notifications. */
11.77
11.78 - /* Convenience method to access object state. */
11.79 -
11.80 - virtual ObjectNotificationState &object_state(notifiable_t *object, bool create);
11.81 -
11.82 - /* Helper methods. */
11.83 -
11.84 - virtual bool _transfer(ObjectNotificationState &state, notifiable_t *object);
11.85 + NotifiableObjectQueue _queued;
11.86 + NotifiableObjects _affected, _monitored;
11.87
11.88 public:
11.89 virtual ~ObjectNotifier();
11.90
11.91 /* Local operations. */
11.92
11.93 - virtual long start();
11.94 -
11.95 - virtual void stop();
11.96 -
11.97 virtual long subscribe(notifiable_t *object, notify_flags_t flags);
11.98
11.99 virtual long unsubscribe(notifiable_t *object);
11.100
11.101 - virtual long remove_endpoint(notifiable_t *object, l4_cap_idx_t endpoint);
11.102 + virtual void update(notifiable_t *object);
11.103 +
11.104 + virtual long wait(notifiable_t **object);
11.105 +
11.106 + virtual long wait_object(notifiable_t *object);
11.107
11.108 /* Helper methods. */
11.109
11.110 - virtual void notify(notifiable_t *object, notify_flags_t flags,
11.111 - notify_values_t values) = 0;
11.112 + virtual void notify(notifiable_t *object);
11.113 +
11.114 + virtual void release(notifiable_t *object);
11.115 };
11.116
11.117
11.118
11.119 -/* An object monitoring notifications for a collection of different objects. */
11.120 -
11.121 -class GeneralObjectNotifier : public ObjectNotifier
11.122 -{
11.123 -protected:
11.124 - /* Locking to protect pending notification members and to coordinate access
11.125 - to notifications. */
11.126 -
11.127 - std::mutex _general_lock;
11.128 -
11.129 - /* General lock synchronisation. */
11.130 -
11.131 - std::condition_variable _general_condition;
11.132 -
11.133 - /* Objects affected by notifications. */
11.134 -
11.135 - std::list<notifiable_t *> _affected;
11.136 -
11.137 - /* Helper methods. */
11.138 -
11.139 - virtual bool _retrieve(notifiable_t **object);
11.140 -
11.141 - virtual bool _retrieve_for_object(notifiable_t *object);
11.142 +/* Collection types. */
11.143
11.144 -public:
11.145 - virtual long wait(notifiable_t **object);
11.146 -
11.147 - /* Helper methods. */
11.148 -
11.149 - virtual void notify(notifiable_t *object, notify_flags_t flags,
11.150 - notify_values_t values);
11.151 -};
11.152 -
11.153 -
11.154 -
11.155 -/* An object monitoring notifications for specific objects. */
11.156 -
11.157 -class SpecificObjectNotifier : public ObjectNotifier
11.158 -{
11.159 -public:
11.160 - virtual long wait_object(notifiable_t *object);
11.161 -
11.162 - /* Helper methods. */
11.163 -
11.164 - virtual void notify(notifiable_t *object, notify_flags_t flags,
11.165 - notify_values_t values);
11.166 -};
11.167 +typedef std::set<ObjectNotifier *> ObjectNotifiers;
11.168
11.169
11.170
11.171 @@ -176,19 +91,35 @@
11.172 class NotifierResource : public Notifier, public Resource
11.173 {
11.174 protected:
11.175 - ObjectNotifier *_notifier;
11.176 + /* Locking for the resource. */
11.177 +
11.178 + std::mutex _lock;
11.179 + std::condition_variable _condition;
11.180 +
11.181 + /* Notifiers and the monitored object. */
11.182 +
11.183 + ObjectNotifiers _notifiers;
11.184 notifiable_t *_object;
11.185
11.186 + /* Utility methods. */
11.187 +
11.188 + virtual void _notify();
11.189 +
11.190 + virtual void _release();
11.191 +
11.192 public:
11.193 - explicit NotifierResource(ObjectNotifier *notifier, notifiable_t *object)
11.194 - : _notifier(notifier), _object(object)
11.195 + l4_cap_idx_t endpoint = L4_INVALID_CAP;
11.196 +
11.197 + explicit NotifierResource(notifiable_t *object)
11.198 + : _object(object)
11.199 {
11.200 }
11.201
11.202 - explicit NotifierResource()
11.203 - : _notifier(NULL), _object(NULL)
11.204 - {
11.205 - }
11.206 + virtual ~NotifierResource();
11.207 +
11.208 + /* Resource methods. */
11.209 +
11.210 + virtual void close();
11.211
11.212 /* Server details. */
11.213
11.214 @@ -200,14 +131,20 @@
11.215 /* Notifier methods. */
11.216
11.217 virtual long notify(notify_flags_t flags, notify_values_t values);
11.218 +
11.219 + /* Local operations. */
11.220 +
11.221 + virtual long add(ObjectNotifier *notifier, notify_flags_t flags);
11.222 +
11.223 + virtual long remove(ObjectNotifier *notifier);
11.224 };
11.225
11.226
11.227
11.228 /* Helper functions. */
11.229
11.230 -SpecificObjectNotifier *notifier_get_task_notifier();
11.231 +ObjectNotifier *notifier_get_task_notifier();
11.232
11.233 -GeneralObjectNotifier *notifier_get_local_notifier();
11.234 +ObjectNotifier *notifier_get_local_notifier();
11.235
11.236 // vim: tabstop=4 expandtab shiftwidth=4
12.1 --- a/libnotifier/lib/src/notifier.cc Fri Apr 07 23:34:59 2023 +0200
12.2 +++ b/libnotifier/lib/src/notifier.cc Fri Apr 07 23:35:21 2023 +0200
12.3 @@ -19,11 +19,6 @@
12.4 * Boston, MA 02110-1301, USA
12.5 */
12.6
12.7 -#include <map>
12.8 -#include <mutex>
12.9 -
12.10 -#include <l4/sys/irq.h>
12.11 -
12.12 #include <ipc/cap_alloc.h>
12.13 #include <ipc/server.h>
12.14 #include <resource/resource_server.h>
12.15 @@ -34,47 +29,35 @@
12.16
12.17
12.18
12.19 -/* Null notification state. */
12.20 -
12.21 -static ObjectNotificationState _null_state;
12.22 -
12.23 -
12.24 -
12.25 /* Lock protecting per-task notifier access. */
12.26
12.27 -static std::mutex _lock;
12.28 +static std::mutex _task_lock;
12.29
12.30 /* Per-task storage for specific waiting operations. */
12.31
12.32 -static SpecificObjectNotifier *_notifier = NULL;
12.33 +static ObjectNotifier *_notifier = NULL;
12.34
12.35
12.36
12.37 /* Return the per-task notifier for object-specific waiting operations. */
12.38
12.39 -SpecificObjectNotifier *notifier_get_task_notifier()
12.40 +ObjectNotifier *notifier_get_task_notifier()
12.41 {
12.42 - std::lock_guard<std::mutex> guard(_lock);
12.43 + std::lock_guard<std::mutex> guard(_task_lock);
12.44
12.45 /* Start any new notifier. */
12.46
12.47 if (_notifier == NULL)
12.48 - {
12.49 - _notifier = new SpecificObjectNotifier;
12.50 - _notifier->start();
12.51 - }
12.52 + _notifier = new ObjectNotifier;
12.53
12.54 return _notifier;
12.55 }
12.56
12.57 /* Return a local notifier for general object waiting operations. */
12.58
12.59 -GeneralObjectNotifier *notifier_get_local_notifier()
12.60 +ObjectNotifier *notifier_get_local_notifier()
12.61 {
12.62 - GeneralObjectNotifier *notifier = new GeneralObjectNotifier;
12.63 -
12.64 - notifier->start();
12.65 - return notifier;
12.66 + return new ObjectNotifier;
12.67 }
12.68
12.69
12.70 @@ -83,358 +66,217 @@
12.71
12.72 ObjectNotifier::~ObjectNotifier()
12.73 {
12.74 - stop();
12.75 + /* Remove this notifier from the individual notifier resources. */
12.76 +
12.77 + NotifiableObjects::iterator it;
12.78
12.79 - ServerConfigs::iterator it;
12.80 + for (it = _monitored.begin(); it != _monitored.end(); it++)
12.81 + {
12.82 + notifiable_t *object = *it;
12.83
12.84 - for (it = _configs.begin(); it != _configs.end(); it++)
12.85 - delete *it;
12.86 + if (object->handler != NULL)
12.87 + {
12.88 + NotifierResource *resource = reinterpret_cast<NotifierResource *>(object->handler);
12.89 + resource->remove(this);
12.90 + }
12.91 + }
12.92
12.93 - _configs.clear();
12.94 + _monitored.clear();
12.95
12.96 /* Handle deletion of the special task notifier. */
12.97
12.98 + std::lock_guard<std::mutex> guard(_task_lock);
12.99 +
12.100 if (this == _notifier)
12.101 _notifier = NULL;
12.102 }
12.103
12.104 -
12.105 -
12.106 -/* Start listening for notifications. */
12.107 -
12.108 -long ObjectNotifier::start()
12.109 -{
12.110 - if (_started)
12.111 - return L4_EOK;
12.112 -
12.113 - /* Create a new thread to serve a "null" resource. This resource is not used
12.114 - for notifications but merely for control purposes. */
12.115 -
12.116 - NotifierResource *notifier = new NotifierResource;
12.117 - ResourceServer server(notifier);
12.118 - long err = server.start_thread(true, false);
12.119 -
12.120 - if (err)
12.121 - return err;
12.122 -
12.123 - _configs.push_back(server.config());
12.124 - _started = true;
12.125 -
12.126 - /* Retain the IRQ created for the server for control purposes. */
12.127 -
12.128 - _irq = server.config()->irq;
12.129 -
12.130 - return L4_EOK;
12.131 -}
12.132 -
12.133 +/* Handle a deletion event for an object. */
12.134
12.135 -
12.136 -/* Stop the notifier. */
12.137 -
12.138 -void ObjectNotifier::stop()
12.139 +void ObjectNotifier::release(notifiable_t *object)
12.140 {
12.141 - if (l4_is_valid_cap(_irq))
12.142 - {
12.143 - l4_irq_trigger(_irq);
12.144 - _irq = L4_INVALID_CAP;
12.145 - }
12.146 -}
12.147 -
12.148 -
12.149 + std::lock_guard<std::mutex> guard(_monitored_lock);
12.150
12.151 -/* Return notification state for the given object or null state if no record
12.152 - existed for the object. */
12.153 -
12.154 -ObjectNotificationState &ObjectNotifier::object_state(notifiable_t *object, bool create)
12.155 -{
12.156 - ObjectNotificationStates::iterator it = _state.find(object);
12.157 -
12.158 - if (it == _state.end())
12.159 - {
12.160 - if (create)
12.161 - return _state[object];
12.162 - else
12.163 - return _null_state;
12.164 - }
12.165 -
12.166 - return it->second;
12.167 + _monitored.erase(object);
12.168 + object->handler = NULL;
12.169 }
12.170
12.171 /* Subscribe to notification events on an object. */
12.172
12.173 long ObjectNotifier::subscribe(notifiable_t *object, notify_flags_t flags)
12.174 {
12.175 - /* Acquire the lock for state lookup. */
12.176 -
12.177 - std::unique_lock<std::mutex> state_guard(_state_lock);
12.178 + std::lock_guard<std::mutex> guard(_monitored_lock);
12.179
12.180 - /* Obtain potentially new state for the object. */
12.181 + /* Ensure that a handler resource is available for object notifications. */
12.182
12.183 - ObjectNotificationState &state = object_state(object, true);
12.184 + NotifierResource *resource;
12.185
12.186 - if (state.is_null())
12.187 - {
12.188 - /* Serve the new object in the notifier thread. */
12.189 + if (object->handler != NULL)
12.190 + resource = reinterpret_cast<NotifierResource *>(object->handler);
12.191 +
12.192 + /* Create a resource if none is recorded. */
12.193
12.194 - NotifierResource *resource = new NotifierResource(this, object);
12.195 + else
12.196 + {
12.197 + resource = new NotifierResource(object);
12.198 ResourceServer server(resource);
12.199 - long err = server.start_in_thread(_configs.front()->thread);
12.200 + long err = server.start_thread(&resource->endpoint);
12.201
12.202 if (err)
12.203 return err;
12.204
12.205 - _configs.push_back(server.config());
12.206 - state.endpoint = server.config()->server;
12.207 + object->handler = resource;
12.208 }
12.209
12.210 - /* Forbid repeated subscription.
12.211 - NOTE: Could instead rely on being unsubscribed, releasing the existing
12.212 - endpoint. */
12.213 + /* Record the object. */
12.214
12.215 - else
12.216 - return -L4_EEXIST;
12.217 + _monitored.insert(object);
12.218
12.219 - /* Allow this object to be re-entered. This may occur because the subscribe
12.220 - operation can cause deferred notifications to be sent back to the
12.221 - subscribed notifier and to this object. */
12.222 -
12.223 - state_guard.unlock();
12.224 + /* Record this notifier to get general notifications. */
12.225
12.226 - /* Subscribe, sending the notification endpoint via the principal reference
12.227 - for the object. */
12.228 -
12.229 - client_Notification notify(object->base->ref);
12.230 -
12.231 - return notify.subscribe(state.endpoint, flags);
12.232 + return resource->add(this, flags);
12.233 }
12.234
12.235 /* Unsubscribe from notification events on an object. */
12.236
12.237 long ObjectNotifier::unsubscribe(notifiable_t *object)
12.238 {
12.239 - /* Acquire the lock for state lookup. */
12.240 + std::lock_guard<std::mutex> guard(_monitored_lock);
12.241 +
12.242 + if (object->handler == NULL)
12.243 + return L4_EOK;
12.244 +
12.245 + NotifierResource *resource = reinterpret_cast<NotifierResource *>(object->handler);
12.246
12.247 - std::unique_lock<std::mutex> state_guard(_state_lock);
12.248 + _monitored.erase(object);
12.249 + object->handler = NULL;
12.250 + return resource->remove(this);
12.251 +}
12.252 +
12.253 +/* Handle a notification event for an object. */
12.254
12.255 - ObjectNotificationState &state = object_state(object, false);
12.256 +void ObjectNotifier::notify(notifiable_t *object)
12.257 +{
12.258 + /* Enter critical section to access the queue. */
12.259 +
12.260 + std::unique_lock<std::mutex> guard(_affected_lock);
12.261 +
12.262 + /* Ensure that a queue entry exists for the object. */
12.263
12.264 - if (state.is_null())
12.265 - return -L4_ENOENT;
12.266 + NotifiableObjects::iterator it = _affected.find(object);
12.267
12.268 - /* Unsubscribe via the notification interface. */
12.269 + if (it == _affected.end())
12.270 + {
12.271 + _queued.push_back(object);
12.272 + _affected.insert(object);
12.273 + }
12.274 +
12.275 + /* Notify all waiting callers that at least one notification is available. */
12.276
12.277 - client_Notification notify(object->base->ref);
12.278 + _condition.notify_all();
12.279 +}
12.280 +
12.281 +/* Update the notifiable object when being notified. */
12.282
12.283 - notify.unsubscribe();
12.284 +void ObjectNotifier::update(notifiable_t *object)
12.285 +{
12.286 + object->notifications = object->pending_notifications;
12.287 + object->values = object->pending_values;
12.288
12.289 - return remove_endpoint(object, state.endpoint);
12.290 + object->pending_notifications = 0;
12.291 }
12.292
12.293 -/* Remove a notification endpoint for an object. */
12.294 +/* Wait for notification events on objects, returning each object that has a
12.295 + notification registered for it. */
12.296 +
12.297 +long ObjectNotifier::wait(notifiable_t **object)
12.298 +{
12.299 + /* Enter critical section to access the queue. */
12.300 +
12.301 + std::unique_lock<std::mutex> guard(_affected_lock);
12.302 +
12.303 + while (1)
12.304 + {
12.305 + /* With pending notifications, return the first object. */
12.306
12.307 -long ObjectNotifier::remove_endpoint(notifiable_t *object, l4_cap_idx_t endpoint)
12.308 -{
12.309 - if (l4_is_invalid_cap(endpoint))
12.310 - return -L4_EINVAL;
12.311 + if (!_affected.empty())
12.312 + {
12.313 + *object = _queued.front();
12.314 + _queued.pop_front();
12.315 + _affected.erase(*object);
12.316 + break;
12.317 + }
12.318 +
12.319 + /* Otherwise, wait for notifications. */
12.320 +
12.321 + _condition.wait(guard);
12.322 + }
12.323 +
12.324 + /* Synchronise the notification flags and values. */
12.325 +
12.326 + update(*object);
12.327 + return L4_EOK;
12.328 +}
12.329 +
12.330 +/* Wait for notification events on a specific object. */
12.331
12.332 - ipc_cap_free_um(endpoint);
12.333 +long ObjectNotifier::wait_object(notifiable_t *object)
12.334 +{
12.335 + /* Enter critical section to access the queue. */
12.336 +
12.337 + std::unique_lock<std::mutex> guard(_affected_lock);
12.338
12.339 - _state.erase(object);
12.340 + while (1)
12.341 + {
12.342 + /* With pending notifications, find any for the specified object. */
12.343 +
12.344 + NotifiableObjects::iterator it = _affected.find(object);
12.345 +
12.346 + if (it != _affected.end())
12.347 + {
12.348 + /* Remove the object from the queue. */
12.349 +
12.350 + NotifiableObjectQueue::iterator itq;
12.351
12.352 - /* Remove the lock for updating object state. */
12.353 + for (itq = _queued.begin(); itq != _queued.end(); itq++)
12.354 + {
12.355 + if (*itq == object)
12.356 + {
12.357 + _queued.erase(itq);
12.358 + break;
12.359 + }
12.360 + }
12.361
12.362 - _object_locks.erase(object);
12.363 + _affected.erase(it);
12.364 + break;
12.365 + }
12.366 +
12.367 + /* Otherwise, wait for notifications. */
12.368
12.369 + _condition.wait(guard);
12.370 + }
12.371 +
12.372 + /* Synchronise the notification flags and values. */
12.373 +
12.374 + update(object);
12.375 return L4_EOK;
12.376 }
12.377
12.378
12.379
12.380 -/* Handle a notification event for an object. */
12.381 -
12.382 -void GeneralObjectNotifier::notify(notifiable_t *object, notify_flags_t flags,
12.383 - notify_values_t values)
12.384 -{
12.385 - /* Enter critical section for the notifier (affecting all objects). */
12.386 -
12.387 - std::unique_lock<std::mutex> general_guard(_general_lock);
12.388 -
12.389 - /* Acquire the lock for state lookup. */
12.390 -
12.391 - std::unique_lock<std::mutex> state_guard(_state_lock);
12.392 -
12.393 - ObjectNotificationState &state = object_state(object, false);
12.394 -
12.395 - if (state.is_null())
12.396 - return;
12.397 -
12.398 - /* Acquire the lock for the object state itself. */
12.399 -
12.400 - std::unique_lock<std::mutex> object_guard(state.lock);
12.401 -
12.402 - /* Record flags and note previous flags. */
12.403 -
12.404 - notify_flags_t recorded = state.pending_notifications;
12.405 -
12.406 - state.pending_notifications |= flags;
12.407 - state.pending_values = values;
12.408 -
12.409 - /* Add an object queue entry for any objects without previous notifications. */
12.410 -
12.411 - if (!recorded)
12.412 - _affected.push_back(object);
12.413 -
12.414 - /* Notify any waiting caller. */
12.415 -
12.416 - _general_condition.notify_one();
12.417 -}
12.418 +/* Virtual destructor required for base class instance reference deletion. */
12.419
12.420 -void SpecificObjectNotifier::notify(notifiable_t *object, notify_flags_t flags,
12.421 - notify_values_t values)
12.422 +NotifierResource::~NotifierResource()
12.423 {
12.424 - /* Acquire the lock for state lookup. */
12.425 -
12.426 - std::unique_lock<std::mutex> state_guard(_state_lock);
12.427 -
12.428 - ObjectNotificationState &state = object_state(object, false);
12.429 -
12.430 - if (state.is_null())
12.431 - return;
12.432 -
12.433 - /* Acquire the lock for the object state itself. */
12.434 -
12.435 - std::unique_lock<std::mutex> object_guard(state.lock);
12.436 -
12.437 - state.pending_notifications |= flags;
12.438 - state.pending_values = values;
12.439 -
12.440 - /* Notify any waiting caller. */
12.441 -
12.442 - state.condition.notify_one();
12.443 -}
12.444 -
12.445 -
12.446 -
12.447 -/* Transfer pending notifications to the given object. This must be called with
12.448 - a lock acquired on the object notification state. */
12.449 -
12.450 -bool ObjectNotifier::_transfer(ObjectNotificationState &state, notifiable_t *object)
12.451 -{
12.452 - notify_flags_t recorded = state.pending_notifications;
12.453 -
12.454 - if (recorded)
12.455 - {
12.456 - object->notifications = recorded;
12.457 - object->values = state.pending_values;
12.458 - state.pending_notifications = 0;
12.459 - return true;
12.460 - }
12.461 -
12.462 - return false;
12.463 }
12.464
12.465 -
12.466 -
12.467 -/* Obtain object state and transfer notifications. */
12.468 -
12.469 -bool GeneralObjectNotifier::_retrieve_for_object(notifiable_t *object)
12.470 -{
12.471 - /* Acquire the lock for state lookup. */
12.472 -
12.473 - std::unique_lock<std::mutex> state_guard(_state_lock);
12.474 -
12.475 - ObjectNotificationState &state = object_state(object, false);
12.476 -
12.477 - if (state.is_null())
12.478 - return false;
12.479 -
12.480 - /* Acquire the lock for the object state itself, then release the state lock. */
12.481 -
12.482 - std::unique_lock<std::mutex> object_guard(state.lock);
12.483 -
12.484 - state_guard.unlock();
12.485 -
12.486 - /* Call generic method to transfer notifications, if possible. */
12.487 -
12.488 - return _transfer(state, object);
12.489 -}
12.490 -
12.491 -/* Obtain queued objects until one is found that still has events recorded for
12.492 - it. This must be called with the notifier's general lock acquired. */
12.493 -
12.494 -bool GeneralObjectNotifier::_retrieve(notifiable_t **object)
12.495 -{
12.496 - while (!_affected.empty())
12.497 - {
12.498 - *object = _affected.front();
12.499 - _affected.pop_front();
12.500 -
12.501 - if (_retrieve_for_object(*object))
12.502 - return true;
12.503 - }
12.504 -
12.505 - return false;
12.506 -}
12.507 -
12.508 -
12.509 -
12.510 -/* Wait for notification events on objects. */
12.511 -
12.512 -long GeneralObjectNotifier::wait(notifiable_t **object)
12.513 -{
12.514 - std::unique_lock<std::mutex> general_guard(_general_lock);
12.515 +/* Handle the release of the resource. */
12.516
12.517 - while (1)
12.518 - {
12.519 - /* With pending notifications, update the first object and exit. */
12.520 -
12.521 - if (_retrieve(object))
12.522 - break;
12.523 -
12.524 - /* Otherwise, wait for notifications. */
12.525 -
12.526 - _general_condition.wait(general_guard);
12.527 - }
12.528 -
12.529 - return L4_EOK;
12.530 -}
12.531 -
12.532 -/* Wait for notifications from a single object. */
12.533 -
12.534 -long SpecificObjectNotifier::wait_object(notifiable_t *object)
12.535 +void NotifierResource::close()
12.536 {
12.537 - /* Acquire the lock for reading object state. */
12.538 -
12.539 - std::unique_lock<std::mutex> state_guard(_state_lock);
12.540 -
12.541 - ObjectNotificationState &state = object_state(object, false);
12.542 -
12.543 - if (state.is_null())
12.544 - return -L4_EINVAL;
12.545 -
12.546 - /* Acquire the lock for the object state itself, then release the state lock. */
12.547 -
12.548 - std::unique_lock<std::mutex> object_guard(state.lock);
12.549 -
12.550 - state_guard.unlock();
12.551 -
12.552 - while (1)
12.553 - {
12.554 - /* With pending notifications, update the object and exit. */
12.555 -
12.556 - if (_transfer(state, object))
12.557 - break;
12.558 -
12.559 - /* Otherwise, wait for notifications. */
12.560 -
12.561 - state.condition.wait(object_guard);
12.562 - }
12.563 -
12.564 - return L4_EOK;
12.565 + _release();
12.566 }
12.567
12.568 -
12.569 -
12.570 /* Object-specific resource methods. */
12.571
12.572 ipc_server_default_config_type NotifierResource::config()
12.573 @@ -442,14 +284,85 @@
12.574 return config_Notifier;
12.575 }
12.576
12.577 +
12.578 +
12.579 +/* Registration of notifiers. */
12.580 +
12.581 +long NotifierResource::add(ObjectNotifier *notifier, notify_flags_t flags)
12.582 +{
12.583 + std::lock_guard<std::mutex> guard(_lock);
12.584 +
12.585 + bool is_new = _notifiers.empty();
12.586 +
12.587 + _notifiers.insert(notifier);
12.588 +
12.589 + /* Subscribe, sending the notification endpoint via the principal reference
12.590 + for the object. */
12.591 +
12.592 + if (!is_new)
12.593 + return L4_EOK;
12.594 +
12.595 + client_Notification notify(_object->base->ref);
12.596 +
12.597 + return notify.subscribe(endpoint, flags);
12.598 +}
12.599 +
12.600 +long NotifierResource::remove(ObjectNotifier *notifier)
12.601 +{
12.602 + std::lock_guard<std::mutex> guard(_lock);
12.603 +
12.604 + _notifiers.erase(notifier);
12.605 +
12.606 + /* Unsubscribe via the notification interface. */
12.607 +
12.608 + if (!_notifiers.empty())
12.609 + return L4_EOK;
12.610 +
12.611 + client_Notification notify(_object->base->ref);
12.612 +
12.613 + return notify.unsubscribe();
12.614 +}
12.615 +
12.616 +
12.617 +
12.618 /* Register a notification received by an object-specific resource. */
12.619
12.620 long NotifierResource::notify(notify_flags_t flags, notify_values_t values)
12.621 {
12.622 - if (_notifier != NULL)
12.623 - _notifier->notify(_object, flags, values);
12.624 + /* Update the notifiable object. */
12.625
12.626 + _object->pending_notifications |= flags;
12.627 + _object->pending_values = values;
12.628 +
12.629 + _notify();
12.630 return L4_EOK;
12.631 }
12.632
12.633 -// vim: tabstop=2 expandtab shiftwidth=2
12.634 +void NotifierResource::_notify()
12.635 +{
12.636 + /* Enter critical section for the resource. */
12.637 +
12.638 + std::lock_guard<std::mutex> guard(_lock);
12.639 +
12.640 + /* Register the notification with all notifier objects. */
12.641 +
12.642 + ObjectNotifiers::iterator it;
12.643 +
12.644 + for (it = _notifiers.begin(); it != _notifiers.end(); it++)
12.645 + (*it)->notify(_object);
12.646 +}
12.647 +
12.648 +void NotifierResource::_release()
12.649 +{
12.650 + /* Enter critical section for the resource. */
12.651 +
12.652 + std::lock_guard<std::mutex> guard(_lock);
12.653 +
12.654 + ObjectNotifiers::iterator it;
12.655 +
12.656 + for (it = _notifiers.begin(); it != _notifiers.end(); it++)
12.657 + (*it)->release(_object);
12.658 +}
12.659 +
12.660 +/* vim: tabstop=2 expandtab shiftwidth=2
12.661 +*/
13.1 --- a/libsystypes/idl/region_mapper.idl Fri Apr 07 23:34:59 2023 +0200
13.2 +++ b/libsystypes/idl/region_mapper.idl Fri Apr 07 23:35:21 2023 +0200
13.3 @@ -15,11 +15,17 @@
13.4 in address_t offset, in unsigned char align);
13.5
13.6 /* Detach memory from the task, searching from the given address for a region
13.7 - of the given size. Return the start address, region size and dataspace. */
13.8 + of the given size. Return the start address, region size and dataspace.
13.9 + Note that the dataspace is returned as an index, not an actual capability.
13.10 +
13.11 + See: pkg/l4re-core/l4re/include/rm
13.12 + See: pkg/l4re-core/l4sys/include/cxx/ipc_iface
13.13 +
13.14 + This is not obvious from the L4Re definitions and the IPC type system. */
13.15
13.16 [opcode(1)] void detach(in address_t addr, in address_t size,
13.17 in map_flags_t flags, out address_t start,
13.18 - out address_t rsize, out cap ds);
13.19 + out address_t rsize, out l4_cap_idx_t ds);
13.20
13.21 /* Find a region starting from the given address and having the given size.
13.22 Return the start address, region size and dataspace. */
14.1 --- a/libsystypes/include/systypes/base.h Fri Apr 07 23:34:59 2023 +0200
14.2 +++ b/libsystypes/include/systypes/base.h Fri Apr 07 23:35:21 2023 +0200
14.3 @@ -49,7 +49,8 @@
14.4
14.5 typedef struct
14.6 {
14.7 - unsigned long sig, val; /* signal-specific values */
14.8 + unsigned long sig; /* signal number */
14.9 + long val; /* signal-specific value */
14.10
14.11 } notify_values_t;
14.12
14.13 @@ -62,6 +63,11 @@
14.14 NOTIFY_PEER_CLOSED = 0x004, /* closing files and pipes */
14.15 NOTIFY_FILE_OPENED = 0x008, /* opening files in directories */
14.16 NOTIFY_TASK_SIGNAL = 0x100, /* signal from task */
14.17 + NOTIFY_TASK_ERROR = 0x200, /* error when creating task */
14.18 +
14.19 + /* Combinations of flags. */
14.20 +
14.21 + NOTIFY_TASK_ALL = 0x300,
14.22 };
14.23
14.24 /* Notifiable object types. */
14.25 @@ -76,7 +82,10 @@
14.26 {
14.27 notifiable_base_t *base; /* access to the specific object */
14.28 notify_flags_t notifications; /* essential notifications */
14.29 + notify_flags_t pending_notifications;
14.30 notify_values_t values; /* signal-specific values */
14.31 + notify_values_t pending_values;
14.32 + void *handler; /* associated notification handler */
14.33
14.34 } notifiable_t;
14.35
15.1 --- a/test_files/programs/clip.c Fri Apr 07 23:34:59 2023 +0200
15.2 +++ b/test_files/programs/clip.c Fri Apr 07 23:35:21 2023 +0200
15.3 @@ -135,14 +135,22 @@
15.4
15.5 i = 1;
15.6 while (i < startline)
15.7 + {
15.8 if (!readline(file, &i, &start, &end))
15.9 - break;
15.10 + {
15.11 + printf("EOF error at line %d.\n", i);
15.12 + return 1;
15.13 + }
15.14 + }
15.15
15.16 while (i < startline + numlines)
15.17 {
15.18 fwrite(start, sizeof(char), end - start, stdout);
15.19 if (!readline(file, &i, &start, &end))
15.20 - break;
15.21 + {
15.22 + printf("EOF error at line %d.\n", i);
15.23 + return 1;
15.24 + }
15.25 }
15.26
15.27 fputs("\n\n", stdout);
16.1 --- a/tests/dstest_exec.cc Fri Apr 07 23:34:59 2023 +0200
16.2 +++ b/tests/dstest_exec.cc Fri Apr 07 23:35:21 2023 +0200
16.3 @@ -28,6 +28,62 @@
16.4
16.5
16.6
16.7 +static long test_process(int argc, const char *argv[])
16.8 +{
16.9 + /* Obtain the common notifier. */
16.10 +
16.11 + process_notifier_t *notifier = process_notify_task();
16.12 +
16.13 + /* Create a new process structure. */
16.14 +
16.15 + process_t process;
16.16 +
16.17 + process_init(&process);
16.18 +
16.19 + /* Start the process. */
16.20 +
16.21 + long err = process_start(&process, argc, argv);
16.22 +
16.23 + if (err)
16.24 + {
16.25 + printf("Could not start process: %s\n", l4sys_errtostr(err));
16.26 + return err;
16.27 + }
16.28 +
16.29 + printf("Finished program initiation.\n");
16.30 +
16.31 + /* Subscribe to the process for notifications. */
16.32 +
16.33 + err = process_notify_subscribe(&process, NOTIFY_TASK_ALL, notifier);
16.34 +
16.35 + if (err)
16.36 + {
16.37 + printf("Could not subscribe to process: %s\n", l4sys_errtostr(err));
16.38 + return err;
16.39 + }
16.40 +
16.41 + /* Wait for a signal from the process. */
16.42 +
16.43 + err = process_notify_wait_process(&process, notifier);
16.44 +
16.45 + if (err)
16.46 + {
16.47 + printf("Could not wait for process: %s\n", l4sys_errtostr(err));
16.48 + return err;
16.49 + }
16.50 +
16.51 + notify_flags_t flags = process_notifications(&process);
16.52 + notify_values_t values = process_notification_values(&process);
16.53 +
16.54 + printf("End process (flags %" pFMTnotify_flags "x values: %ld, %ld)\n", flags, values.sig, values.val);
16.55 +
16.56 + err = process_error(&process);
16.57 + process_close(&process);
16.58 + return err;
16.59 +}
16.60 +
16.61 +
16.62 +
16.63 int main(int argc, char *argv[])
16.64 {
16.65 long err;
16.66 @@ -42,52 +98,30 @@
16.67
16.68 process_notifier_t *notifier = process_notify_task();
16.69
16.70 - /* Create a new process structure. */
16.71 -
16.72 - process_t process;
16.73 + /* Start a process for a non-existent program. */
16.74
16.75 - process_init(&process);
16.76 + printf("Start non-existent program...\n");
16.77
16.78 - printf("Start process...\n");
16.79 + const char *bad_argv[] = {"non_existent_program"};
16.80
16.81 - /* Start a process for the given program. */
16.82 -
16.83 - err = process_start(&process, argc - 1, argv + 1);
16.84 + err = test_process(1, bad_argv);
16.85
16.86 - if (err)
16.87 + if (!err)
16.88 {
16.89 - printf("Could not start process: %s\n", l4sys_errtostr(err));
16.90 + printf("Non-existent program was apparently successfully started.\n");
16.91 return 1;
16.92 }
16.93
16.94 - printf("Finished program initiation.\n");
16.95 + printf("Non-existent program result: %s\n", l4sys_errtostr(err));
16.96 +
16.97 + /* Start a process for the given program. */
16.98
16.99 - /* Subscribe to the process for notifications. */
16.100 + printf("Start process...\n");
16.101
16.102 - err = process_notify_subscribe(&process, NOTIFY_TASK_SIGNAL, notifier);
16.103 + err = test_process(argc - 1, (const char **) argv + 1);
16.104
16.105 if (err)
16.106 - {
16.107 - printf("Could not subscribe to process: %s\n", l4sys_errtostr(err));
16.108 return 1;
16.109 - }
16.110 -
16.111 - /* Wait for a signal from the process. */
16.112 -
16.113 - err = process_notify_wait_process(&process, notifier);
16.114 -
16.115 - if (err)
16.116 - {
16.117 - printf("Could not wait for process: %s\n", l4sys_errtostr(err));
16.118 - return 1;
16.119 - }
16.120 -
16.121 - notify_flags_t flags = process_notifications(&process);
16.122 - notify_values_t values = process_notification_values(&process);
16.123 -
16.124 - process_close(&process);
16.125 -
16.126 - printf("End process (flags %" pFMTnotify_flags "x values: %ld, %ld)\n", flags, values.sig, values.val);
16.127
16.128 process_notify_close(notifier);
16.129
17.1 --- a/tests/dstest_exec_many.cc Fri Apr 07 23:34:59 2023 +0200
17.2 +++ b/tests/dstest_exec_many.cc Fri Apr 07 23:35:21 2023 +0200
17.3 @@ -57,7 +57,7 @@
17.4
17.5 /* Start a process for the given program. */
17.6
17.7 - err = process_start(&process, argc - 2, argv + 2);
17.8 + err = process_start(&process, argc - 2, (const char **) argv + 2);
17.9
17.10 if (err)
17.11 {
17.12 @@ -69,7 +69,7 @@
17.13
17.14 /* Subscribe to the process for notifications. */
17.15
17.16 - err = process_notify_subscribe(&process, NOTIFY_TASK_SIGNAL, notifier);
17.17 + err = process_notify_subscribe(&process, NOTIFY_TASK_ALL, notifier);
17.18
17.19 if (err)
17.20 {
17.21 @@ -90,9 +90,9 @@
17.22 notify_flags_t flags = process_notifications(&process);
17.23 notify_values_t values = process_notification_values(&process);
17.24
17.25 - process_close(&process);
17.26 + printf("[%d/%d] End process (flags %" pFMTnotify_flags "x values: %ld, %ld)\n", i, num_processes, flags, values.sig, values.val);
17.27
17.28 - printf("[%d/%d] End process (flags %" pFMTnotify_flags "x values: %ld, %ld)\n", i, num_processes, flags, values.sig, values.val);
17.29 + process_close(&process);
17.30 }
17.31
17.32 process_notify_close(notifier);
18.1 --- a/tests/dstest_file_monitor.cc Fri Apr 07 23:34:59 2023 +0200
18.2 +++ b/tests/dstest_file_monitor.cc Fri Apr 07 23:35:21 2023 +0200
18.3 @@ -56,6 +56,7 @@
18.4 {
18.5 sprintf(buffer, "%s/file%02d", filename, i);
18.6
18.7 + printf("Open file %d.\n", i);
18.8 client_open(buffer, O_CREAT | O_RDWR);
18.9 sleep(1);
18.10 }
18.11 @@ -65,21 +66,13 @@
18.12
18.13 static void monitor_files(file_t *directory)
18.14 {
18.15 - long err = client_subscribe(directory, NOTIFY_FILE_OPENED, client_notifier_task());
18.16 -
18.17 - if (err)
18.18 - {
18.19 - printf("Could not subscribe to events on directory.\n");
18.20 - return;
18.21 - }
18.22 -
18.23 int expected;
18.24
18.25 for (expected = FILES_TO_OPEN; expected; expected--)
18.26 {
18.27 /* Wait for notification of content. */
18.28
18.29 - err = client_wait_file(directory, client_notifier_task());
18.30 + long err = client_wait_file(directory, client_notifier_task());
18.31
18.32 if (err)
18.33 {
18.34 @@ -116,6 +109,14 @@
18.35 return 1;
18.36 }
18.37
18.38 + long err = client_subscribe(directory, NOTIFY_FILE_OPENED, client_notifier_task());
18.39 +
18.40 + if (err)
18.41 + {
18.42 + printf("Could not subscribe to events on directory.\n");
18.43 + return 1;
18.44 + }
18.45 +
18.46 /* Schedule threads. */
18.47
18.48 std::thread *activities[2];
18.49 @@ -127,6 +128,9 @@
18.50 activities[i]->join();
18.51
18.52 printf("Expected %d 'file opened' notifications.\n", FILES_TO_OPEN);
18.53 +
18.54 + client_close(directory);
18.55 +
18.56 printf("End of test.\n");
18.57 return 0;
18.58 }
19.1 --- a/tests/dstest_pipe_client.cc Fri Apr 07 23:34:59 2023 +0200
19.2 +++ b/tests/dstest_pipe_client.cc Fri Apr 07 23:35:21 2023 +0200
19.3 @@ -154,8 +154,8 @@
19.4
19.5 for (int p = 0; p < 2; p++)
19.6 {
19.7 - printf("Data received for pipe #%d: " FMToffsetd "\n", p, totals[p]);
19.8 - printf("Data shown for pipe #%d: %s\n", p, totals[p] == TO_TRANSFER * 26 * NUMBER_OF_ITERATIONS ? "True" : "False");
19.9 + printf("Data received for pipe #%d: " FMToffsetd "\n", p + 1, totals[p]);
19.10 + printf("Data shown for pipe #%d: %s\n", p + 1, totals[p] == TO_TRANSFER * 26 * NUMBER_OF_ITERATIONS ? "True" : "False");
19.11 }
19.12 }
19.13