AT: Added freeze to handle modem transport failure properly
authorPaul Kocialkowski <contact@paulk.fr>
Fri, 31 Aug 2012 15:30:47 +0000 (17:30 +0200)
committerPaul Kocialkowski <contact@paulk.fr>
Fri, 31 Aug 2012 15:30:47 +0000 (17:30 +0200)
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
at.c
at.h
device.c
hayes-ril.c

diff --git a/at.c b/at.c
index b4c5018..b0d47c9 100644 (file)
--- a/at.c
+++ b/at.c
@@ -779,6 +779,11 @@ struct at_response *at_response_dequeue(void)
                AT_RESPONSES_QUEUE_LOCK();
                AT_RESPONSES_LOCK();
 
+               if(at_freeze_get() == AT_FREEZE_SEND) {
+                       AT_RESPONSES_UNLOCK();
+                       return NULL;
+               }
+
                // Get the new data pointer and count
                responses = at_handling.responses_queue.responses;
                responses_count = at_handling.responses_queue.responses_count;
@@ -962,6 +967,9 @@ void at_async_request_free(struct at_async_request *async_request)
        if(async_request->command)
                free(async_request->command);
 
+       if(async_request->request)
+               at_request_free(async_request->request);
+
        memset(async_request, 0, sizeof(struct at_async_request));
        async_request->handled = AT_RESPONSE_GARBAGE;
 }
@@ -1307,6 +1315,9 @@ void at_sync_request_free(struct at_sync_request *sync_request)
        if(sync_request->command)
                free(sync_request->command);
 
+       if(sync_request->request)
+               at_request_free(sync_request->request);
+
        memset(sync_request, 0, sizeof(struct at_sync_request));
        sync_request->handled = AT_RESPONSE_GARBAGE;
 }
@@ -1650,6 +1661,114 @@ int at_sync_request_dequeue(struct at_sync_request *sync_request)
 }
 
 /*
+ * Freeze
+ */
+
+void at_freeze_set(int freeze)
+{
+       at_handling.freeze = freeze;
+}
+
+int at_freeze_get(void)
+{
+       return at_handling.freeze;
+}
+
+int at_freeze_start(void)
+{
+       struct at_sync_request *sync_request = NULL;
+       struct at_async_request *async_request = NULL;
+
+       at_freeze_set(AT_FREEZE_ON);
+
+       // Set all the sent requests to freezed state
+       sync_request = at_sync_request_find_handled(AT_RESPONSE_SENT);
+       if(sync_request)
+               sync_request->handled = AT_RESPONSE_SENT_FREEZED;
+
+       async_request = at_async_request_find_handled(AT_RESPONSE_SENT);
+       if(async_request)
+               async_request->handled = AT_RESPONSE_SENT_FREEZED;
+
+       async_request = at_async_request_find_handled(AT_RESPONSE_UNHANDELD_REASON_STATUS);
+       if(async_request)
+               async_request->handled = AT_RESPONSE_SENT_FREEZED;
+
+       async_request = at_async_request_find_handled(AT_RESPONSE_UNHANDELD_REASON_DATA);
+       if(async_request)
+               async_request->handled = AT_RESPONSE_SENT_FREEZED;
+
+       return 0;
+}
+
+int at_freeze_stop(void)
+{
+       at_freeze_set(AT_FREEZE_OFF);
+
+       return 0;
+}
+
+int at_freeze_send(void)
+{
+       // Allow requests send even though there are freezed requests
+       at_freeze_set(AT_FREEZE_SEND);
+
+       // Unlock responses queue so that the dispatch loop can send setup
+       AT_RESPONSES_QUEUE_UNLOCK();
+
+       return 0;
+}
+
+int at_freeze_respawn(void)
+{
+       struct at_sync_request *sync_request = NULL;
+       struct at_async_request *async_request = NULL;
+       int rc;
+
+       // Respawn the latest request
+       at_freeze_set(AT_FREEZE_RESPAWN);
+
+       // There should only be one
+       do {
+               sync_request = at_sync_request_find_handled(AT_RESPONSE_SENT_FREEZED);
+               if(sync_request) {
+                       sync_request->handled = AT_RESPONSE_WAITING;
+
+                       rc = at_request_queue(sync_request->request);
+                       if(rc < 0) {
+                               LOGE("Unable to queue request");
+
+                               // Better trying to dequeue too
+                               at_sync_request_dequeue(sync_request);
+                               at_sync_request_free(sync_request);
+                       } else {
+                               at_send_next_request();
+                       }
+               }
+       } while(sync_request != NULL);
+
+       do {
+               async_request = at_async_request_find_handled(AT_RESPONSE_SENT_FREEZED);
+               if(async_request) {
+                       async_request->handled = AT_RESPONSE_WAITING;
+
+                       rc = at_request_queue(async_request->request);
+                       if(rc < 0) {
+                               LOGE("Unable to queue request");
+
+                               // Better trying to dequeue too
+                               at_async_request_dequeue(async_request);
+                               at_async_request_free(async_request);
+                       } else {
+                               at_send_next_request();
+                       }
+               }
+       } while(async_request != NULL);
+
+       return 0;
+}
+
+/*
  * Request
  */
 
@@ -1775,6 +1894,9 @@ int at_request_send_async(struct at_request *request, void *data, RIL_Token toke
        async_request->token = token;
        async_request->func = func;
 
+       if(at_freeze_get() == AT_FREEZE_SEND)
+               async_request->handled = AT_RESPONSE_UNFREEZE;
+
        rc = at_async_request_queue(async_request);
        if(rc < 0) {
                LOGE("Unable to queue async request");
@@ -1783,6 +1905,10 @@ int at_request_send_async(struct at_request *request, void *data, RIL_Token toke
                return -1;
        }
 
+       // Do not queue the request when sending while freeze
+       if(at_freeze_get() == AT_FREEZE_SEND)
+               goto request_send;
+
        rc = at_request_queue(request);
        if(rc < 0) {
                LOGE("Unable to queue request");
@@ -1793,6 +1919,7 @@ int at_request_send_async(struct at_request *request, void *data, RIL_Token toke
                return NULL;
        }
 
+request_send:
        // Try to send it now, don't fail if it can't
        at_send_next_request();
 
@@ -1814,6 +1941,9 @@ struct at_response *at_request_send_sync(struct at_request *request)
        sync_request->request = request;
        sync_request->command = strdup(request->command);
 
+       if(at_freeze_get() == AT_FREEZE_SEND)
+               sync_request->handled = AT_RESPONSE_UNFREEZE;
+
        rc = at_sync_request_queue(sync_request);
        if(rc < 0) {
                LOGE("Unable to queue sync request");
@@ -1822,6 +1952,10 @@ struct at_response *at_request_send_sync(struct at_request *request)
                return NULL;
        }
 
+       // Do not queue the request when sending while freeze
+       if(at_freeze_get() == AT_FREEZE_SEND)
+               goto request_send;
+
        rc = at_request_queue(request);
        if(rc < 0) {
                LOGE("Unable to queue request");
@@ -1832,6 +1966,7 @@ struct at_response *at_request_send_sync(struct at_request *request)
                return NULL;
        }
 
+request_send:
        // Try to send it now, don't fail if it can't
        at_send_next_request();
 
@@ -1875,6 +2010,25 @@ int at_send_next_request(void)
        struct at_request *request = NULL;
        int rc;
 
+       if(at_freeze_get() == AT_FREEZE_SEND) {
+               sync_request = at_sync_request_find_handled(AT_RESPONSE_UNFREEZE);
+               if(sync_request != NULL) {
+                       request = sync_request->request;
+                       goto request_send;
+               }
+
+               async_request = at_async_request_find_handled(AT_RESPONSE_UNFREEZE);
+               if(async_request != NULL) {
+                       request = async_request->request;
+                       goto request_send;
+               }
+
+               if(request == NULL) {
+                       LOGD("No request to send during freeze!");
+                       return -1;
+               }
+       }
+
        // Unhandled requests are still going on too
        sync_request = at_sync_request_find_handled(AT_RESPONSE_SENT);
        async_request_sent = at_async_request_find_handled(AT_RESPONSE_SENT);
@@ -1892,6 +2046,7 @@ int at_send_next_request(void)
                return -1;
        }
 
+request_send:
        rc = at_request_send(request);
        if(rc < 0) {
                LOGE("Unable to send request, aborting!");
@@ -1900,18 +2055,12 @@ int at_send_next_request(void)
        }
 
        sync_request = at_sync_request_find_request(request);
-       if(sync_request != NULL) {
+       if(sync_request != NULL)
                sync_request->handled = AT_RESPONSE_SENT;
-               sync_request->request = NULL;
-       }
 
        async_request = at_async_request_find_request(request);
-       if(async_request != NULL) {
+       if(async_request != NULL)
                async_request->handled = AT_RESPONSE_SENT;
-               async_request->request = NULL;
-       }
-
-       at_request_free(request);
 
        return 0;
 }
diff --git a/at.h b/at.h
index d0c9ed6..e9ebf69 100644 (file)
--- a/at.h
+++ b/at.h
@@ -146,9 +146,18 @@ enum {
        AT_RESPONSE_UNHANDELD_REASON_STATUS,
        AT_RESPONSE_HANDLED_OK,
        AT_RESPONSE_HANDLED_ERROR,
+       AT_RESPONSE_SENT_FREEZED,
+       AT_RESPONSE_UNFREEZE,
        AT_RESPONSE_GARBAGE,
 };
 
+enum {
+       AT_FREEZE_OFF,
+       AT_FREEZE_ON,
+       AT_FREEZE_SEND,
+       AT_FREEZE_RESPAWN,
+};
+
 typedef int (*at_async_request_cb)(struct at_response *response, void *data, RIL_Token t);
 
 struct at_sync_request {
@@ -203,6 +212,8 @@ struct at_async_requests_queue {
 };
 
 struct at_handling {
+       int freeze;
+
        struct at_responses_queue responses_queue;
        struct at_requests_queue requests_queue;
 
@@ -260,6 +271,14 @@ void at_request_free(struct at_request *request);
 int at_request_send_async(struct at_request *request, void *data, RIL_Token token, at_async_request_cb func);
 struct at_response *at_request_send_sync(struct at_request *request);
 
+// Freeze
+void at_freeze_set(int freeze);
+int at_freeze_get(void);
+int at_freeze_start(void);
+int at_freeze_stop(void);
+int at_freeze_send(void);
+int at_freeze_respawn(void);
+
 // Send
 int at_send_next_request(void);
 struct at_response *at_send_sync(char *command, char *data);
index 4e3ddbb..1993e48 100644 (file)
--- a/device.c
+++ b/device.c
@@ -494,10 +494,21 @@ int ril_device_transport_recv_loop(struct ril_device *ril_device_p)
                        free(data);
                }
 
+               // Freeze all the sent requests
+               at_freeze_start();
+
                // When poll/read failed, close and reopen the device
                ril_device_transport_close(ril_device_p);
-               usleep(500);
-               ril_device_transport_open(ril_device_p);
+               rc = ril_device_transport_open(ril_device_p);
+               if(rc < 0) {
+                       LOGE("Unable to reopen transport");
+               } else {
+                       at_freeze_send();
+                       at_freeze_respawn();
+               }
+
+               // Unfreeze all the requests
+               at_freeze_stop();
 
                RIL_DEVICE_UNLOCK(ril_device_p);
        }
index d7b2eef..50b4701 100644 (file)
@@ -128,8 +128,13 @@ void *ril_dispatch(void *data)
        for(i = 5 ; i > 0 ; i--) {
                while(1) {
                        response = at_response_dequeue();
-                       if(response == NULL)
+
+                       if(response == NULL && at_freeze_get() == AT_FREEZE_SEND) {
+                               ril_device_at_setup(ril_device);
+                               continue;
+                       } else if(response == NULL) {
                                break;
+                       }
 
                        // Dequeue works now
                        if(i != 5)