introspecting.c 9.76 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
  introspecting.c -- LabComm example of a twoway stacked introspection 
                     reader/writer.

  Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se>

  This file is part of LabComm.

  LabComm is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  LabComm is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "labcomm_private.h"
#include "introspecting.h"
#include "gen/introspecting_messages.h"

struct introspecting_private {
  struct introspecting introspecting;
Anders Blomdell's avatar
Anders Blomdell committed
32
  struct labcomm_error_handler *error;
33
  struct labcomm_memory *memory;
Anders Blomdell's avatar
Anders Blomdell committed
34
  struct labcomm_scheduler *scheduler;
35

36
37
  struct labcomm_reader_action_context reader_action_context;
  struct labcomm_writer_action_context writer_action_context;
38
39
40
41
42
43
44
45
  LABCOMM_SIGNATURE_ARRAY_DEF(remote, 
			      struct remote {
				char *name;
				int size;
				uint8_t *signature;
			      });
  LABCOMM_SIGNATURE_ARRAY_DEF(local, 
			      struct local {
Anders Blomdell's avatar
Anders Blomdell committed
46
				enum introspecting_status status;
47
				const struct labcomm_signature *signature;
48
49
50
			      });
};

Anders Blomdell's avatar
Anders Blomdell committed
51
52
static struct local *get_local(struct introspecting_private *introspecting,
			       int index,
53
			       const struct labcomm_signature *signature)
Anders Blomdell's avatar
Anders Blomdell committed
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
{
  /* Called with data_lock held */
  struct local *local;
  
  local = LABCOMM_SIGNATURE_ARRAY_REF(introspecting->memory,
				      introspecting->local, 
				      struct local, 
				      index);
  if (local->signature == NULL) {
    local->signature = signature;
    local->status = introspecting_unknown;
  }  
  if (local->status == introspecting_unknown) {
    int i;

    local->status = introspecting_unhandled;
    LABCOMM_SIGNATURE_ARRAY_FOREACH(introspecting->remote, struct remote, i) {
      struct remote *r;
      
      r = LABCOMM_SIGNATURE_ARRAY_REF(introspecting->memory,
				      introspecting->remote, struct remote, i);
      if (r->name && 
	  strcmp(signature->name, r->name) == 0 &&
	  r->size == signature->size &&
	  memcmp(signature->signature, r->signature, signature->size) == 0) {
	local->status = introspecting_unregistered;
	break;
      }
    }
  }
  return local;
}

87
88
89
90
91
static void handles_signature(
  introspecting_messages_handles_signature *value,
  void * context)
{
  struct introspecting_private *introspecting = context;
92
93
  struct remote *remote;

Anders Blomdell's avatar
Anders Blomdell committed
94
  labcomm_scheduler_data_lock(introspecting->scheduler);
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  remote = LABCOMM_SIGNATURE_ARRAY_REF(introspecting->memory,
				       introspecting->remote, 
				       struct remote, 
				       value->index);
  remote->name = strdup(value->name);
  remote->signature = malloc(value->signature.n_0);
  if (remote->signature) {
    int i;

    memcpy(remote->signature, value->signature.a, value->signature.n_0);
    remote->size = value->signature.n_0;
    LABCOMM_SIGNATURE_ARRAY_FOREACH(introspecting->local, struct local, i) {
      struct local *l;
      
      l = LABCOMM_SIGNATURE_ARRAY_REF(introspecting->memory,
				      introspecting->local, struct local, i);
      if (l->signature && 
Anders Blomdell's avatar
Anders Blomdell committed
112
	  l->status == introspecting_unhandled &&
113
114
115
116
117
	  l->signature->name && 
	  strcmp(remote->name, l->signature->name) == 0 &&
	  remote->size == l->signature->size &&
	  memcmp(l->signature->signature, remote->signature, 
		 l->signature->size) == 0) {
Anders Blomdell's avatar
Anders Blomdell committed
118
	l->status = introspecting_unregistered;
119
120
121
      }
    }
  }
Anders Blomdell's avatar
Anders Blomdell committed
122
  labcomm_scheduler_data_unlock(introspecting->scheduler);
123
124
125
126
}

static int wrap_reader_alloc(
  struct labcomm_reader *r, 
127
  struct labcomm_reader_action_context *action_context)
128
129
130
131
{
  struct introspecting_private *introspecting = action_context->context;

  labcomm_decoder_register_introspecting_messages_handles_signature(
Anders Blomdell's avatar
Anders Blomdell committed
132
133
    introspecting->introspecting.reader->decoder, 
    handles_signature, introspecting);
134
  return labcomm_reader_alloc(r, action_context->next);
135
136
}

Anders Blomdell's avatar
Anders Blomdell committed
137
138
139
struct handles_signature {
  struct introspecting_private *introspecting;
  int index;
140
  const struct labcomm_signature *signature;
Anders Blomdell's avatar
Anders Blomdell committed
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
};

static void send_handles_signature(void *arg)
{
  struct handles_signature *h = arg;

  introspecting_messages_handles_signature handles_signature;
  handles_signature.index = h->index;
  handles_signature.name = h->signature->name;
  handles_signature.signature.n_0 = h->signature->size;
  handles_signature.signature.a = h->signature->signature;
  labcomm_encode_introspecting_messages_handles_signature(
    h->introspecting->introspecting.writer->encoder, &handles_signature);
}

156
157
158
static int wrap_reader_start(
  struct labcomm_reader *r, 
  struct labcomm_reader_action_context *action_context,
159
  int local_index, int remote_index, const struct labcomm_signature *signature,
160
161
162
  void *value)
{
  struct introspecting_private *introspecting = action_context->context;
163
164
  
  if (value == NULL) {
Anders Blomdell's avatar
Anders Blomdell committed
165
166
167
168
169
170
171
172
173
    struct handles_signature *handles_signature;

    handles_signature = labcomm_memory_alloc(introspecting->memory, 1,
					     sizeof(*handles_signature));
    handles_signature->introspecting = introspecting;
    handles_signature->index = local_index;
    handles_signature->signature = signature;
    labcomm_scheduler_enqueue(introspecting->scheduler, 
			      0, send_handles_signature, handles_signature);
174
  }
Anders Blomdell's avatar
Anders Blomdell committed
175
176
  return labcomm_reader_start(r, action_context->next, 
			      local_index, remote_index, signature, value);
177
178
179
180
181
182
}

 void encode_handles_signature(
  struct labcomm_encoder *encoder,
  void *context)
{
183
  const struct labcomm_signature *signature = context;
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  introspecting_messages_handles_signature handles_signature;
  int index = 0;

  handles_signature.index = index;
  handles_signature.name = signature->name;
  handles_signature.signature.n_0 = signature->size;
  handles_signature.signature.a = signature->signature;

  labcomm_encode_introspecting_messages_handles_signature(
    NULL, &handles_signature);
}

struct labcomm_reader_action introspecting_reader_action = {
  .alloc = wrap_reader_alloc,
  .free = NULL,
  .start = wrap_reader_start,
  .end = NULL,
  .fill = NULL,
  .ioctl = NULL
};

Anders Blomdell's avatar
Anders Blomdell committed
205
static void register_encoder_signatures(void *context)
206
{
Anders Blomdell's avatar
Anders Blomdell committed
207
208
  struct introspecting_private *introspecting = context;

209
  labcomm_encoder_register_introspecting_messages_handles_signature(
Anders Blomdell's avatar
Anders Blomdell committed
210
    introspecting->introspecting.writer->encoder);
211
212
213
214
}

static int wrap_writer_alloc(
  struct labcomm_writer *w, 
215
  struct labcomm_writer_action_context *action_context)
216
217
218
{
  struct introspecting_private *introspecting = action_context->context;

Anders Blomdell's avatar
Anders Blomdell committed
219
220
  labcomm_scheduler_enqueue(introspecting->scheduler, 
			    0, register_encoder_signatures, introspecting);
221
  return labcomm_writer_alloc(w, action_context->next);
222
223
224
225
226
}

static int wrap_writer_start(
  struct labcomm_writer *w, 
  struct labcomm_writer_action_context *action_context, 
227
  int index, const struct labcomm_signature *signature,
228
229
  void *value)
{
230
231
  struct introspecting_private *introspecting = action_context->context;

232
  if (index >= LABCOMM_USER && value == NULL) {
Anders Blomdell's avatar
Anders Blomdell committed
233
234
235
236
237
238
    struct local *local;

    labcomm_scheduler_data_lock(introspecting->scheduler);
    local = get_local(introspecting, index, signature);
    local->status = introspecting_registered;
    labcomm_scheduler_data_unlock(introspecting->scheduler);
239
  }
Anders Blomdell's avatar
Anders Blomdell committed
240
241
  return labcomm_writer_start(w, action_context->next, index, signature, value);
}
242

Anders Blomdell's avatar
Anders Blomdell committed
243
244
245
static int wrap_writer_ioctl(
  struct labcomm_writer *w, 
  struct labcomm_writer_action_context *action_context, 
246
  int index, const struct labcomm_signature *signature, 
Anders Blomdell's avatar
Anders Blomdell committed
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  uint32_t ioctl_action, va_list args)
{
  struct introspecting_private *introspecting = action_context->context;

  switch (ioctl_action) {
    case HAS_SIGNATURE: {
      struct local *local;
      int result;

      labcomm_scheduler_data_lock(introspecting->scheduler);
      local = get_local(introspecting, index, signature);
      result = local->status;
      labcomm_scheduler_data_unlock(introspecting->scheduler);
      return result;
261
    }
Anders Blomdell's avatar
Anders Blomdell committed
262
263
264
265
    default: {
      return labcomm_writer_ioctl(w, action_context->next, index, signature, 
				  ioctl_action, args);  
    } break;
266
  }
267
268
269
270
271
272
273
274
}

struct labcomm_writer_action introspecting_writer_action = {
  .alloc = wrap_writer_alloc,
  .free = NULL, 
  .start = wrap_writer_start,
  .end = NULL,
  .flush = NULL,
Anders Blomdell's avatar
Anders Blomdell committed
275
  .ioctl = wrap_writer_ioctl
276
277
278
279
280
};

extern struct introspecting *introspecting_new(
  struct labcomm_reader *reader,
  struct labcomm_writer *writer,
Anders Blomdell's avatar
Anders Blomdell committed
281
282
283
  struct labcomm_error_handler *error,
  struct labcomm_memory *memory,
  struct labcomm_scheduler *scheduler)
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
{
  struct introspecting_private *result;

  result = malloc(sizeof(*result));
  if (result == NULL) {
    goto out_fail;
  }

  /* Wrap reader and writer */
  result->reader_action_context.next = reader->action_context;
  result->reader_action_context.action = &introspecting_reader_action;
  result->reader_action_context.context = result;
  reader->action_context = &result->reader_action_context;

  result->writer_action_context.next = writer->action_context;
  result->writer_action_context.action = &introspecting_writer_action;
  result->writer_action_context.context = result;
  writer->action_context = &result->writer_action_context;

  /* Init visible result struct */
  result->introspecting.reader = reader;
  result->introspecting.writer = writer;

  /* Init other fields */
Anders Blomdell's avatar
Anders Blomdell committed
308
  result->error = error;
309
  result->memory = memory;
Anders Blomdell's avatar
Anders Blomdell committed
310
  result->scheduler = scheduler;
311
312
  LABCOMM_SIGNATURE_ARRAY_INIT(result->remote, struct remote);
  LABCOMM_SIGNATURE_ARRAY_INIT(result->local, struct local);
313
314
315
316
317
318
319
320
321
322
323

  goto out_ok;

out_fail:
  return NULL;

out_ok:
  return &result->introspecting;
}