dpif-linux: Fix segfault when a port already exists.
[sliver-openvswitch.git] / ovsdb / trigger.c
1 /* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <config.h>
17
18 #include "trigger.h"
19
20 #include <limits.h>
21
22 #include "json.h"
23 #include "jsonrpc.h"
24 #include "ovsdb.h"
25 #include "poll-loop.h"
26 #include "server.h"
27
28 static bool ovsdb_trigger_try(struct ovsdb_trigger *, long long int now);
29 static void ovsdb_trigger_complete(struct ovsdb_trigger *);
30
31 void
32 ovsdb_trigger_init(struct ovsdb_session *session, struct ovsdb *db,
33                    struct ovsdb_trigger *trigger,
34                    struct json *request, long long int now)
35 {
36     trigger->session = session;
37     trigger->db = db;
38     list_push_back(&trigger->db->triggers, &trigger->node);
39     trigger->request = request;
40     trigger->result = NULL;
41     trigger->created = now;
42     trigger->timeout_msec = LLONG_MAX;
43     ovsdb_trigger_try(trigger, now);
44 }
45
46 void
47 ovsdb_trigger_destroy(struct ovsdb_trigger *trigger)
48 {
49     list_remove(&trigger->node);
50     json_destroy(trigger->request);
51     json_destroy(trigger->result);
52 }
53
54 bool
55 ovsdb_trigger_is_complete(const struct ovsdb_trigger *trigger)
56 {
57     return trigger->result != NULL;
58 }
59
60 struct json *
61 ovsdb_trigger_steal_result(struct ovsdb_trigger *trigger)
62 {
63     struct json *result = trigger->result;
64     trigger->result = NULL;
65     return result;
66 }
67
68 void
69 ovsdb_trigger_run(struct ovsdb *db, long long int now)
70 {
71     struct ovsdb_trigger *t, *next;
72     bool run_triggers;
73
74     run_triggers = db->run_triggers;
75     db->run_triggers = false;
76     LIST_FOR_EACH_SAFE (t, next, node, &db->triggers) {
77         if (run_triggers || now - t->created >= t->timeout_msec) {
78             ovsdb_trigger_try(t, now);
79         }
80     }
81 }
82
83 void
84 ovsdb_trigger_wait(struct ovsdb *db, long long int now)
85 {
86     if (db->run_triggers) {
87         poll_immediate_wake();
88     } else {
89         long long int deadline = LLONG_MAX;
90         struct ovsdb_trigger *t;
91
92         LIST_FOR_EACH (t, node, &db->triggers) {
93             if (t->created < LLONG_MAX - t->timeout_msec) {
94                 long long int t_deadline = t->created + t->timeout_msec;
95                 if (deadline > t_deadline) {
96                     deadline = t_deadline;
97                     if (now >= deadline) {
98                         break;
99                     }
100                 }
101             }
102         }
103
104         if (deadline < LLONG_MAX) {
105             poll_timer_wait_until(deadline);
106         }
107     }
108 }
109
110 static bool
111 ovsdb_trigger_try(struct ovsdb_trigger *t, long long int now)
112 {
113     t->result = ovsdb_execute(t->db, t->session,
114                               t->request, now - t->created, &t->timeout_msec);
115     if (t->result) {
116         ovsdb_trigger_complete(t);
117         return true;
118     } else {
119         return false;
120     }
121 }
122
123 static void
124 ovsdb_trigger_complete(struct ovsdb_trigger *t)
125 {
126     ovs_assert(t->result != NULL);
127     list_remove(&t->node);
128     list_push_back(&t->session->completions, &t->node);
129 }