0

I have a program that uses channels for inter-process messaging.It is driving me nuts.

When I run my program by typing:

spin ipc_verify.pml

It works fine (shown by the prints in my program) and exits gracefully as designed. However, when I try to verify by doing the following:

spin -a ipc-verify.pml
gcc -DVECTORSZ=4096 -DVERBOSE -o pan pan.c
./pan 

It fails in the first statement in the server where the server is trying to read on the channel, with the error:

pan:1: missing pars in receive (at depth 20)

It seems like I am missing something very simple, but can't put my finger on it. I am new to Spin, doing it as part of my coursework, so please pardon if it is a simple, silly question.

Here is a brief description of the program: The program starts 3 processes - 1 server and 2 clients. Client sends a number to the server, which responds with the square of the number. There is a request channel on which every client send its request (message has the client id using which server knows which client to respond to), and a response channel on which server sends the response to the clients. Clients use random receive on the channel to find the message for their id.

The code line where I believe it fails is this

:: ch_clientrequest ? msgtype, client_id, client_request ->

I actually have a bigger program that exhibits this behavior so I tried to reproduce it in this program. I read through various ways of seeing more data about from spin about this error, and also googled around. Also tried changing the message structure, more fields, less fields, not doing random receive but regular receive, etc. Nothing seems to change this error!

Here is the full error trace from running ./pan:

pan:1: missing pars in receive (at depth 20)
pan: wrote ipc-verify.pml.trail

(Spin Version 6.5.1 -- 20 December 2019)
Warning: Search not completed
        + Partial Order Reduction
        + FullStack Matching

Full statespace search for:
        never claim             - (none specified)
        assertion violations    +
        acceptance   cycles     - (not selected)
        invalid end states      +

State-vector 2104 byte, depth reached 20, errors: 1
       21 states, stored
        0 states, matched
        0 matches within stack
       21 transitions (= stored+matched)
        0 atomic steps
hash conflicts:         0 (resolved)
stackframes: 0/0

stats: fa 0, fh 0, zh 0, zn 0 - check 0 holds 0
stack stats: puts 0, probes 0, zaps 0
Stats on memory usage (in Megabytes):
    0.043       equivalent memory usage for states (stored*(State-vector + overhead))
    1.164       actual memory usage for states
  128.000       memory used for hash table (-w24)
    0.534       memory used for DFS stack (-m10000)
  129.315       total actual memory usage

I have tried to look for what this message at run-time in verification means, but couldn't find much. Based on various experimentation of code, it seems that the verifier thinks that the message I am trying to receive is supposed to have more parameters than what I am trying to read for. I tried to see if it is reacting to the actual message received and maybe that has less fields, but that doesn't seem to be the case.

I have been banging my head on this for full day today, with no leads. Any pointers or ideas to solve this would be very appreciated. I am running this on my linux box, Spin 6.5.

/*
One hub controller (server), 8 clients. 
Each client sends a message to the hub, hub responds with the message it received. 
*/

#define N 2 // Number of clients
#define MQLENGTH 100
mtype = {START_CLIENT, COMPUTE_REQUEST, COMPUTE_RESPONSE, STOP_CLIENT, STOP_HUB}

typedef ClientRequest {
    byte num;
}

typedef HubResponse {
    bool isNull; // To indicate whether there is data or not. Set True for START and STOP messages
    int id;
    byte num;
    int sqnum;
}

typedef IdList {
    byte ids[N]; // Use to store the ids assigned to each client process
}

IdList idlist;


chan ch_clientrequest = [MQLENGTH] of {mtype, byte, ClientRequest} // Hub listens to this
chan ch_hubresponse = [MQLENGTH] of {mtype, byte, HubResponse} // Clients read from this

int message_served = 0


proctype Client(byte id) {
    // A client reads the message and responds to it
    mtype msgtype
    HubResponse hub_response
    ClientRequest client_request

    do
    :: ch_hubresponse ?? msgtype, eval(id), hub_response ->
        printf("\nClient Id: %d, Received - MsgType: %e", id, msgtype)
        if
        :: (msgtype == COMPUTE_RESPONSE) ->
            // print the message
            printf("\nClient Id: %d, Received - num = %d, sqnum = %d", id, hub_response.num, hub_response.sqnum)
            // send another message. new num = sqnum
            client_request.num = hub_response.sqnum % 256// To keep it as byte
            if
            :: (client_request.num < 2) ->
                client_request.num = 2
            :: else ->
                skip
            fi

            ch_clientrequest ! COMPUTE_REQUEST(id, client_request)
            printf("\nClient Id: %d, Sent - num = %d", id, client_request.num)


        :: (msgtype == STOP_CLIENT) ->
            // break from the do loop
            break;
        :: (msgtype == START_CLIENT) ->
            client_request.num = id // Start with num = id
            ch_clientrequest ! COMPUTE_REQUEST(id, client_request)
            printf("\nClient Id: %d, Sent - num = %d", id, client_request.num)

        fi

    od

    printf("\nClient exiting. Id = %d", id)

}

proctype Hub() {
    // Hub sends a start message to each client, and then keeps responding to what it receives
    HubResponse hr
    ClientRequest client_request
    mtype msgtype
    byte client_id
    int i
    byte num


    for (i: 0 .. ( N - 1) ) {
        // Send a start message
        hr.isNull = true

        ch_hubresponse ! START_CLIENT(idlist.ids[i], hr) // Send a start message
    }
    // All of the clients have been started. Now wait for the message and respond appropriately
    do
    :: ch_clientrequest ? msgtype, client_id, client_request ->
        printf("\nHub Controller. Received - MsgType: %e", msgtype)
        if
        :: (msgtype == COMPUTE_REQUEST) ->
            // handle the message
            num = client_request.num
            hr.isNull = false
            hr.id = client_id
            hr.num = num
            hr.sqnum = num * num
            ch_hubresponse ! COMPUTE_RESPONSE(client_id, hr) // Send a response message
            message_served ++

        :: (msgtype == STOP_HUB) ->
            // break from the do loop, send stop message to all clients, and exit
            break;
        fi

    od

    // loop through the ids and send stop message
    for (i: 0 .. ( N - 1) ) {
        // Send a start message
        hr.isNull = true
        ch_hubresponse ! STOP_CLIENT(idlist.ids[i], hr) // Send a start message
    }

    printf("\nServer exiting.") 
}

active proctype Main() {
    // Start the clients and give them an id to use
    ClientRequest c
    pid n;
    n = _nr_pr;
    byte i

    for (i: 1.. N ) {
        run Client(i)
        idlist.ids[i-1] = i
    }

    // Start the hub and give it the list of ids

    run Hub()


    // Send a message to Hub to stop serving
    (message_served >= 100);
    ch_clientrequest ! STOP_HUB(0, c) 

    // Wait for all processes to exit
    (n == _nr_pr); 
    printf("\nAll processes have exited!")
}
  • I have never seen this error message, but it looks like this might be caused by the combination of a *typedef* message parameter, *message filtering* and also *random receive*. It is hard to say whether you are violating some design rule or it is a bug. Hence, I would submit your problem as an issue at their [github page](https://github.com/nimble-code/Spin. – Patrick Trentin May 03 '20 at 16:13
  • Thanks @PatrickTrentin, I will do so. – Mrityunjay Kumar May 04 '20 at 09:58
  • 1
    After some more investigation, it looks like there is some problem with random receive - particularly eval(id). For now, I have removed this and replaced it with one channel per receiver rather than both of them receiving from the same channel via random receive. So I am out of the woods for now, but still need to figure out what happened. Will ask on their github as suggested by @PatrickTrentin – Mrityunjay Kumar May 04 '20 at 10:00
  • Yeah that is what I observed yesterday. But I have used message filtering in the past, and I have never observed such an anomaly. That is why I speculated that it might also have something to do with one of the other two *uncommon* features you are using. – Patrick Trentin May 04 '20 at 10:04

0 Answers0