1 /*
2  * Copyright (c) 2012-2016 Cisco Systems, Inc.  All rights reserved.
3  * Copyright (c) 2012      Los Alamos National Security, LLC. All rights reserved
4  * Copyright (c) 2015      Intel, Inc. All rights reserved
5  * $COPYRIGHT$
6  *
7  * Additional copyrights may follow
8  *
9  * $HEADER$
10  */
11 
12 #include "opal_config.h"
13 
14 #include <stdio.h>
15 #include <stddef.h>
16 
17 #include "opal/mca/event/event.h"
18 #include "opal/class/opal_hotel.h"
19 
20 
local_eviction_callback(int fd,short flags,void * arg)21 static void local_eviction_callback(int fd, short flags, void *arg)
22 {
23     opal_hotel_room_eviction_callback_arg_t *eargs =
24         (opal_hotel_room_eviction_callback_arg_t*) arg;
25     void *occupant = eargs->hotel->rooms[eargs->room_num].occupant;
26 
27     /* Remove the occurpant from the room.
28 
29        Do not change this logic without also changing the same logic
30        in opal_hotel_checkout() and
31        opal_hotel_checkout_and_return_occupant(). */
32     opal_hotel_t *hotel = eargs->hotel;
33     opal_hotel_room_t *room = &(hotel->rooms[eargs->room_num]);
34     room->occupant = NULL;
35     hotel->last_unoccupied_room++;
36     assert(hotel->last_unoccupied_room < hotel->num_rooms);
37     hotel->unoccupied_rooms[hotel->last_unoccupied_room] = eargs->room_num;
38 
39     /* Invoke the user callback to tell them that they were evicted */
40     hotel->evict_callback_fn(hotel,
41                              eargs->room_num,
42                              occupant);
43 }
44 
45 
opal_hotel_init(opal_hotel_t * h,int num_rooms,opal_event_base_t * evbase,uint32_t eviction_timeout,int eviction_event_priority,opal_hotel_eviction_callback_fn_t evict_callback_fn)46 int opal_hotel_init(opal_hotel_t *h, int num_rooms,
47                     opal_event_base_t *evbase,
48                     uint32_t eviction_timeout,
49                     int eviction_event_priority,
50                     opal_hotel_eviction_callback_fn_t evict_callback_fn)
51 {
52     int i;
53 
54     /* Bozo check */
55     if (num_rooms <= 0 ||
56         NULL == evict_callback_fn) {
57         return OPAL_ERR_BAD_PARAM;
58     }
59 
60     h->num_rooms = num_rooms;
61     h->evbase = evbase;
62     h->eviction_timeout.tv_usec = eviction_timeout % 1000000;
63     h->eviction_timeout.tv_sec = eviction_timeout / 1000000;
64     h->evict_callback_fn = evict_callback_fn;
65     h->rooms = (opal_hotel_room_t*)malloc(num_rooms * sizeof(opal_hotel_room_t));
66     if (NULL != evict_callback_fn) {
67         h->eviction_args =
68             (opal_hotel_room_eviction_callback_arg_t*)malloc(num_rooms * sizeof(opal_hotel_room_eviction_callback_arg_t));
69     }
70     h->unoccupied_rooms = (int*) malloc(num_rooms * sizeof(int));
71     h->last_unoccupied_room = num_rooms - 1;
72 
73     for (i = 0; i < num_rooms; ++i) {
74         /* Mark this room as unoccupied */
75         h->rooms[i].occupant = NULL;
76 
77         /* Setup this room in the unoccupied index array */
78         h->unoccupied_rooms[i] = i;
79 
80         /* Setup the eviction callback args */
81         h->eviction_args[i].hotel = h;
82         h->eviction_args[i].room_num = i;
83 
84         /* Create this room's event (but don't add it) */
85         if (NULL != h->evbase) {
86             opal_event_set(h->evbase,
87                            &(h->rooms[i].eviction_timer_event),
88                            -1, 0, local_eviction_callback,
89                            &(h->eviction_args[i]));
90 
91             /* Set the priority so it gets serviced properly */
92             opal_event_set_priority(&(h->rooms[i].eviction_timer_event),
93                                     eviction_event_priority);
94         }
95     }
96 
97     return OPAL_SUCCESS;
98 }
99 
constructor(opal_hotel_t * h)100 static void constructor(opal_hotel_t *h)
101 {
102     h->num_rooms = 0;
103     h->evbase = NULL;
104     h->eviction_timeout.tv_sec = 0;
105     h->eviction_timeout.tv_usec = 0;
106     h->evict_callback_fn = NULL;
107     h->rooms = NULL;
108     h->eviction_args = NULL;
109     h->unoccupied_rooms = NULL;
110     h->last_unoccupied_room = -1;
111 }
112 
destructor(opal_hotel_t * h)113 static void destructor(opal_hotel_t *h)
114 {
115     int i;
116 
117     /* Go through all occupied rooms and destroy their events */
118     if (NULL != h->evbase) {
119         for (i = 0; i < h->num_rooms; ++i) {
120             if (NULL != h->rooms[i].occupant) {
121                 opal_event_del(&(h->rooms[i].eviction_timer_event));
122             }
123         }
124     }
125 
126     if (NULL != h->rooms) {
127         free(h->rooms);
128     }
129     if (NULL != h->eviction_args) {
130         free(h->eviction_args);
131     }
132     if (NULL != h->unoccupied_rooms) {
133         free(h->unoccupied_rooms);
134     }
135 }
136 
137 OBJ_CLASS_INSTANCE(opal_hotel_t,
138                    opal_object_t,
139                    constructor,
140                    destructor);
141