Skip to content

Parallel Libtrace HOWTO: Stopping Callback

Shane Alcock edited this page Sep 21, 2015 · 4 revisions

The stopping callback is invoked immediately prior to the termination of a libtrace thread. No packets will be read by the thread once the stopping callback is called. The typical use of a stopping callback is to flush any final unpublished results and release any memory that was allocated by the starting callback.

In our example scenario, we need to push our counters through to the reporter thread so that the results for each thread can be tallied and free the counter structure. Based on that, code for our stopping callback is given below:

/* Structure that describes a result from a processing thread */
struct udpresult {
    uint64_t payload;
    uint64_t packets;
};

static void stop_processing(libtrace_t *trace, libtrace_thread_t *thread,
        void *global, void *tls) {

    struct udpresult *u;

    /* Cast our local storage to the right structure */
    struct counters *c = (struct counters *)tls;

    /* Create a new result object to pass into the reporter. Note
     * this is malloc'd memory so the reporter must free it. */
    u = (struct udpresult *)malloc(sizeof(struct udpresult));

    /* Populate our result structure */
    u->packets = c->packets;
    u->payload = c->payload;

    /* Publish the result */
    trace_publish_result(trace, thread, 0, (libtrace_generic_t){.ptr=u}, 
            RESULT_USER);

    /* Free our thread local storage */
    free(c);
}

Let's look at a few of the new concepts introduced here:

  • The udpresult structure To collate our results, we're going to need a couple of values from each thread: the average payload size and the packet count (because not all threads may see an equal number of packets). Eagle-eyed readers will have noticed that this structure is the same as the counters structure that we've been using as thread local storage. We could have re-used the structure in this case, but there are reasons for not doing so that will become clearer as our example program develops.
  • trace_publish_result This function tells libtrace to push a given result through to the combiner thread. It takes 5 parameters: 1. the input trace, 2. the thread that is publishing, 3. a key indicating the relative order for the result, 4. the result itself, and 5. the type of result.
  • Publishing keys The third parameter to trace_publish_result is a key that can be used by the combiner to work out the correct order to pass results on to the reporter thread. For instance, an ordered combiner will make sure that results will reach the reporter in ascending order of key -- this is important if publishing packets and you want them to remain in timestamp order; the timestamp would be used as the key. In this example, we don't really care about ordering so all of our threads will publish with key 0.
  • libtrace_generic_t Because results can take on any form, i.e. they can be packets, structures, integers or floating point numbers, we have defined a special type called libtrace_generic_t which is essentially a union of all types that are supported internally. Our result is best represented as a pointer to a structure, so we use the .ptr form.
  • Result types These are used to indicate the type of result to the reporter thread. If the result is a packet, you use RESULT_PACKET. If the result is a user-defined structure, you use RESULT_USER.
  • Parameters and return values for a stopping callback The four parameters taken by the stopping callback are parameters that we've already seen before. A stopping callback must return void.

Now that we are publishing results, let's start thinking about the reporter thread.

Clone this wiki locally