dapl: move close device after async thread is done using it
[mirror/winof/.git] / ulp / dapl2 / dapl / openib_scm / device.c
1 /*\r
2  * This Software is licensed under one of the following licenses:\r
3  *\r
4  * 1) under the terms of the "Common Public License 1.0" a copy of which is\r
5  *    available from the Open Source Initiative, see\r
6  *    http://www.opensource.org/licenses/cpl.php.\r
7  *\r
8  * 2) under the terms of the "The BSD License" a copy of which is\r
9  *    available from the Open Source Initiative, see\r
10  *    http://www.opensource.org/licenses/bsd-license.php.\r
11  *\r
12  * 3) under the terms of the "GNU General Public License (GPL) Version 2" a\r
13  *    copy of which is available from the Open Source Initiative, see\r
14  *    http://www.opensource.org/licenses/gpl-license.php.\r
15  *\r
16  * Licensee has the right to choose one of the above licenses.\r
17  *\r
18  * Redistributions of source code must retain the above copyright\r
19  * notice and one of the license notices.\r
20  *\r
21  * Redistributions in binary form must reproduce both the above copyright\r
22  * notice, one of the license notices in the documentation\r
23  * and/or other materials provided with the distribution.\r
24  */\r
25 \r
26 /***************************************************************************\r
27  *\r
28  *   Module:             uDAPL\r
29  *\r
30  *   Filename:           dapl_ib_util.c\r
31  *\r
32  *   Author:             Arlin Davis\r
33  *\r
34  *   Created:            3/10/2005\r
35  *\r
36  *   Description: \r
37  *\r
38  *   The uDAPL openib provider - init, open, close, utilities\r
39  *\r
40  ****************************************************************************\r
41  *                 Source Control System Information\r
42  *\r
43  *    $Id: $\r
44  *\r
45  *      Copyright (c) 2005 Intel Corporation.  All rights reserved.\r
46  *\r
47  **************************************************************************/\r
48 #ifdef RCSID\r
49 static const char rcsid[] = "$Id:  $";\r
50 #endif\r
51 \r
52 #include "openib_osd.h"\r
53 #include "dapl.h"\r
54 #include "dapl_adapter_util.h"\r
55 #include "dapl_ib_util.h"\r
56 #include "dapl_osd.h"\r
57 \r
58 #include <stdlib.h>\r
59 \r
60 ib_thread_state_t g_ib_thread_state = 0;\r
61 DAPL_OS_THREAD g_ib_thread;\r
62 DAPL_OS_LOCK g_hca_lock;\r
63 struct dapl_llist_entry *g_hca_list;\r
64 \r
65 void dapli_thread(void *arg);\r
66 DAT_RETURN  dapli_ib_thread_init(void);\r
67 void dapli_ib_thread_destroy(void);\r
68 \r
69 #if defined(_WIN64) || defined(_WIN32)\r
70 #include "..\..\..\..\..\etc\user\comp_channel.cpp"\r
71 #include <rdma\winverbs.h>\r
72 \r
73 static COMP_SET ufds;\r
74 \r
75 static int dapls_os_init(void)\r
76 {\r
77         return CompSetInit(&ufds);\r
78 }\r
79 \r
80 static void dapls_os_release(void)\r
81 {\r
82         CompSetCleanup(&ufds);\r
83 }\r
84 \r
85 static int dapls_config_verbs(struct ibv_context *verbs)\r
86 {\r
87         verbs->channel.Milliseconds = 0;\r
88         return 0;\r
89 }\r
90 \r
91 static int dapls_config_comp_channel(struct ibv_comp_channel *channel)\r
92 {\r
93         channel->comp_channel.Milliseconds = 0;\r
94         return 0;\r
95 }\r
96 \r
97 static int dapls_thread_signal(void)\r
98 {\r
99         CompSetCancel(&ufds);\r
100         return 0;\r
101 }\r
102 #else                           // _WIN64 || WIN32\r
103 int g_ib_pipe[2];\r
104 \r
105 static int dapls_os_init(void)\r
106 {\r
107         /* create pipe for waking up work thread */\r
108         return pipe(g_ib_pipe);\r
109 }\r
110 \r
111 static void dapls_os_release(void)\r
112 {\r
113         /* close pipe? */\r
114 }\r
115 \r
116 static int dapls_config_fd(int fd)\r
117 {\r
118         int opts;\r
119 \r
120         opts = fcntl(fd, F_GETFL);\r
121         if (opts < 0 || fcntl(fd, F_SETFL, opts | O_NONBLOCK) < 0) {\r
122                 dapl_log(DAPL_DBG_TYPE_ERR,\r
123                          " dapls_config_fd: fcntl on fd %d ERR %d %s\n",\r
124                          fd, opts, strerror(errno));\r
125                 return errno;\r
126         }\r
127 \r
128         return 0;\r
129 }\r
130 \r
131 static int dapls_config_verbs(struct ibv_context *verbs)\r
132 {\r
133         return dapls_config_fd(verbs->async_fd);\r
134 }\r
135 \r
136 static int dapls_config_comp_channel(struct ibv_comp_channel *channel)\r
137 {\r
138         return dapls_config_fd(channel->fd);\r
139 }\r
140 \r
141 static int dapls_thread_signal(void)\r
142 {\r
143         return write(g_ib_pipe[1], "w", sizeof "w");\r
144 }\r
145 #endif\r
146 \r
147 \r
148 static int32_t create_cr_pipe(IN DAPL_HCA * hca_ptr)\r
149 {\r
150         DAPL_SOCKET listen_socket;\r
151         struct sockaddr_in addr;\r
152         socklen_t addrlen = sizeof(addr);\r
153         int ret;\r
154 \r
155         listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);\r
156         if (listen_socket == DAPL_INVALID_SOCKET)\r
157                 return 1;\r
158 \r
159         memset(&addr, 0, sizeof addr);\r
160         addr.sin_family = AF_INET;\r
161         addr.sin_addr.s_addr = htonl(0x7f000001);\r
162         ret = bind(listen_socket, (struct sockaddr *)&addr, sizeof addr);\r
163         if (ret)\r
164                 goto err1;\r
165 \r
166         ret = getsockname(listen_socket, (struct sockaddr *)&addr, &addrlen);\r
167         if (ret)\r
168                 goto err1;\r
169 \r
170         ret = listen(listen_socket, 0);\r
171         if (ret)\r
172                 goto err1;\r
173 \r
174         hca_ptr->ib_trans.scm[1] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);\r
175         if (hca_ptr->ib_trans.scm[1] == DAPL_INVALID_SOCKET)\r
176                 goto err1;\r
177 \r
178         ret = connect(hca_ptr->ib_trans.scm[1], \r
179                       (struct sockaddr *)&addr, sizeof(addr));\r
180         if (ret)\r
181                 goto err2;\r
182 \r
183         hca_ptr->ib_trans.scm[0] = accept(listen_socket, NULL, NULL);\r
184         if (hca_ptr->ib_trans.scm[0] == DAPL_INVALID_SOCKET)\r
185                 goto err2;\r
186 \r
187         closesocket(listen_socket);\r
188         return 0;\r
189 \r
190       err2:\r
191         closesocket(hca_ptr->ib_trans.scm[1]);\r
192       err1:\r
193         closesocket(listen_socket);\r
194         return 1;\r
195 }\r
196 \r
197 static void destroy_cr_pipe(IN DAPL_HCA * hca_ptr)\r
198 {\r
199         closesocket(hca_ptr->ib_trans.scm[0]);\r
200         closesocket(hca_ptr->ib_trans.scm[1]);\r
201 }\r
202 \r
203 \r
204 /*\r
205  * dapls_ib_init, dapls_ib_release\r
206  *\r
207  * Initialize Verb related items for device open\r
208  *\r
209  * Input:\r
210  *      none\r
211  *\r
212  * Output:\r
213  *      none\r
214  *\r
215  * Returns:\r
216  *      0 success, -1 error\r
217  *\r
218  */\r
219 int32_t dapls_ib_init(void)\r
220 {\r
221         /* initialize hca_list */\r
222         dapl_os_lock_init(&g_hca_lock);\r
223         dapl_llist_init_head(&g_hca_list);\r
224 \r
225         if (dapls_os_init())\r
226                 return 1;\r
227 \r
228         return 0;\r
229 }\r
230 \r
231 int32_t dapls_ib_release(void)\r
232 {\r
233         dapli_ib_thread_destroy();\r
234         dapls_os_release();\r
235         return 0;\r
236 }\r
237 \r
238 /*\r
239  * dapls_ib_open_hca\r
240  *\r
241  * Open HCA\r
242  *\r
243  * Input:\r
244  *      *hca_name         pointer to provider device name\r
245  *      *ib_hca_handle_p  pointer to provide HCA handle\r
246  *\r
247  * Output:\r
248  *      none\r
249  *\r
250  * Return:\r
251  *      DAT_SUCCESS\r
252  *      dapl_convert_errno\r
253  *\r
254  */\r
255 DAT_RETURN dapls_ib_open_hca(IN IB_HCA_NAME hca_name, IN DAPL_HCA * hca_ptr)\r
256 {\r
257         struct ibv_device **dev_list;\r
258         struct ibv_port_attr port_attr;\r
259         int i;\r
260         DAT_RETURN dat_status;\r
261 \r
262         dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
263                      " open_hca: %s - %p\n", hca_name, hca_ptr);\r
264 \r
265         /* get the IP address of the device */\r
266         dat_status = getlocalipaddr((DAT_SOCK_ADDR *) &hca_ptr->hca_address,\r
267                                     sizeof(DAT_SOCK_ADDR6));\r
268         if (dat_status != DAT_SUCCESS)\r
269                 return dat_status;\r
270 \r
271 #ifdef DAPL_DBG\r
272         /* DBG: unused port, set process id, lower 16 bits of pid */\r
273         ((struct sockaddr_in *)&hca_ptr->hca_address)->sin_port = \r
274                                         htons((uint16_t)dapl_os_getpid());\r
275 #endif\r
276         /* Get list of all IB devices, find match, open */\r
277         dev_list = ibv_get_device_list(NULL);\r
278         if (!dev_list) {\r
279                 dapl_dbg_log(DAPL_DBG_TYPE_ERR,\r
280                              " open_hca: ibv_get_device_list() failed\n",\r
281                              hca_name);\r
282                 return DAT_INTERNAL_ERROR;\r
283         }\r
284 \r
285         for (i = 0; dev_list[i]; ++i) {\r
286                 hca_ptr->ib_trans.ib_dev = dev_list[i];\r
287                 if (!strcmp(ibv_get_device_name(hca_ptr->ib_trans.ib_dev),\r
288                             hca_name))\r
289                         goto found;\r
290         }\r
291 \r
292         dapl_log(DAPL_DBG_TYPE_ERR,\r
293                  " open_hca: device %s not found\n", hca_name);\r
294         goto err;\r
295 \r
296 found:\r
297         dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " open_hca: Found dev %s %016llx\n",\r
298                      ibv_get_device_name(hca_ptr->ib_trans.ib_dev),\r
299                      (unsigned long long)\r
300                      ntohll(ibv_get_device_guid(hca_ptr->ib_trans.ib_dev)));\r
301 \r
302         hca_ptr->ib_hca_handle = ibv_open_device(hca_ptr->ib_trans.ib_dev);\r
303         if (!hca_ptr->ib_hca_handle) {\r
304                 dapl_log(DAPL_DBG_TYPE_ERR,\r
305                          " open_hca: dev open failed for %s, err=%s\n",\r
306                          ibv_get_device_name(hca_ptr->ib_trans.ib_dev),\r
307                          strerror(errno));\r
308                 goto err;\r
309         }\r
310         hca_ptr->ib_trans.ib_ctx = hca_ptr->ib_hca_handle;\r
311         dapls_config_verbs(hca_ptr->ib_hca_handle);\r
312 \r
313         /* get lid for this hca-port, network order */\r
314         if (ibv_query_port(hca_ptr->ib_hca_handle,\r
315                            (uint8_t) hca_ptr->port_num, &port_attr)) {\r
316                 dapl_log(DAPL_DBG_TYPE_ERR,\r
317                          " open_hca: get lid ERR for %s, err=%s\n",\r
318                          ibv_get_device_name(hca_ptr->ib_trans.ib_dev),\r
319                          strerror(errno));\r
320                 goto err;\r
321         } else {\r
322                 hca_ptr->ib_trans.lid = htons(port_attr.lid);\r
323         }\r
324 \r
325         /* get gid for this hca-port, network order */\r
326         if (ibv_query_gid(hca_ptr->ib_hca_handle,\r
327                           (uint8_t) hca_ptr->port_num,\r
328                           0, &hca_ptr->ib_trans.gid)) {\r
329                 dapl_log(DAPL_DBG_TYPE_ERR,\r
330                          " open_hca: query GID ERR for %s, err=%s\n",\r
331                          ibv_get_device_name(hca_ptr->ib_trans.ib_dev),\r
332                          strerror(errno));\r
333                 goto err;\r
334         }\r
335 \r
336         /* set RC tunables via enviroment or default */\r
337         hca_ptr->ib_trans.max_inline_send =\r
338             dapl_os_get_env_val("DAPL_MAX_INLINE", INLINE_SEND_DEFAULT);\r
339         hca_ptr->ib_trans.ack_retry =\r
340             dapl_os_get_env_val("DAPL_ACK_RETRY", SCM_ACK_RETRY);\r
341         hca_ptr->ib_trans.ack_timer =\r
342             dapl_os_get_env_val("DAPL_ACK_TIMER", SCM_ACK_TIMER);\r
343         hca_ptr->ib_trans.rnr_retry =\r
344             dapl_os_get_env_val("DAPL_RNR_RETRY", SCM_RNR_RETRY);\r
345         hca_ptr->ib_trans.rnr_timer =\r
346             dapl_os_get_env_val("DAPL_RNR_TIMER", SCM_RNR_TIMER);\r
347         hca_ptr->ib_trans.global =\r
348             dapl_os_get_env_val("DAPL_GLOBAL_ROUTING", SCM_GLOBAL);\r
349         hca_ptr->ib_trans.hop_limit =\r
350             dapl_os_get_env_val("DAPL_HOP_LIMIT", SCM_HOP_LIMIT);\r
351         hca_ptr->ib_trans.tclass =\r
352             dapl_os_get_env_val("DAPL_TCLASS", SCM_TCLASS);\r
353         hca_ptr->ib_trans.mtu =\r
354             dapl_ib_mtu(dapl_os_get_env_val("DAPL_IB_MTU", SCM_IB_MTU));\r
355 \r
356 \r
357         /* EVD events without direct CQ channels, CNO support */\r
358         hca_ptr->ib_trans.ib_cq =\r
359             ibv_create_comp_channel(hca_ptr->ib_hca_handle);\r
360         if (hca_ptr->ib_trans.ib_cq == NULL) {\r
361                 dapl_log(DAPL_DBG_TYPE_ERR,\r
362                          " open_hca: ibv_create_comp_channel ERR %s\n",\r
363                          strerror(errno));\r
364                 goto bail;\r
365         }\r
366         dapls_config_comp_channel(hca_ptr->ib_trans.ib_cq);\r
367         \r
368         dat_status = dapli_ib_thread_init();\r
369         if (dat_status != DAT_SUCCESS) {\r
370                 dapl_log(DAPL_DBG_TYPE_ERR,\r
371                          " open_hca: failed to init cq thread lock\n");\r
372                 goto bail;\r
373         }\r
374         /* \r
375          * Put new hca_transport on list for async and CQ event processing \r
376          * Wakeup work thread to add to polling list\r
377          */\r
378         dapl_llist_init_entry((DAPL_LLIST_ENTRY *)&hca_ptr->ib_trans.entry);\r
379         dapl_os_lock(&g_hca_lock);\r
380         dapl_llist_add_tail(&g_hca_list,\r
381                             (DAPL_LLIST_ENTRY *) &hca_ptr->ib_trans.entry,\r
382                             &hca_ptr->ib_trans.entry);\r
383         if (dapls_thread_signal() == -1)\r
384                 dapl_log(DAPL_DBG_TYPE_UTIL,\r
385                          " open_hca: thread wakeup error = %s\n",\r
386                          strerror(errno));\r
387         dapl_os_unlock(&g_hca_lock);\r
388 \r
389         /* initialize cr_list lock */\r
390         dat_status = dapl_os_lock_init(&hca_ptr->ib_trans.lock);\r
391         if (dat_status != DAT_SUCCESS) {\r
392                 dapl_log(DAPL_DBG_TYPE_ERR,\r
393                          " open_hca: failed to init cr_list lock\n");\r
394                 goto bail;\r
395         }\r
396 \r
397         /* initialize CM list for listens on this HCA */\r
398         dapl_llist_init_head(&hca_ptr->ib_trans.list);\r
399 \r
400         /* initialize pipe, user level wakeup on select */\r
401         if (create_cr_pipe(hca_ptr)) {\r
402                 dapl_log(DAPL_DBG_TYPE_ERR,\r
403                          " open_hca: failed to init cr pipe - %s\n",\r
404                          strerror(errno));\r
405                 goto bail;\r
406         }\r
407 \r
408         /* create thread to process inbound connect request */\r
409         hca_ptr->ib_trans.cr_state = IB_THREAD_INIT;\r
410         dat_status = dapl_os_thread_create(cr_thread,\r
411                                            (void *)hca_ptr,\r
412                                            &hca_ptr->ib_trans.thread);\r
413         if (dat_status != DAT_SUCCESS) {\r
414                 dapl_log(DAPL_DBG_TYPE_ERR,\r
415                          " open_hca: failed to create thread\n");\r
416                 goto bail;\r
417         }\r
418 \r
419         /* wait for thread */\r
420         while (hca_ptr->ib_trans.cr_state != IB_THREAD_RUN) {\r
421                 dapl_os_sleep_usec(1000);\r
422         }\r
423 \r
424         dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
425                      " open_hca: devname %s, port %d, hostname_IP %s\n",\r
426                      ibv_get_device_name(hca_ptr->ib_trans.ib_dev),\r
427                      hca_ptr->port_num, inet_ntoa(((struct sockaddr_in *)\r
428                                                    &hca_ptr->hca_address)->\r
429                                                   sin_addr));\r
430         dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
431                      " open_hca: LID 0x%x GID Subnet 0x" F64x " ID 0x" F64x\r
432                      "\n", ntohs(hca_ptr->ib_trans.lid), (unsigned long long)\r
433                      htonll(hca_ptr->ib_trans.gid.global.subnet_prefix),\r
434                      (unsigned long long)htonll(hca_ptr->ib_trans.gid.global.\r
435                                                 interface_id));\r
436 \r
437         ibv_free_device_list(dev_list);\r
438         return dat_status;\r
439 \r
440       bail:\r
441         ibv_close_device(hca_ptr->ib_hca_handle);\r
442         hca_ptr->ib_hca_handle = IB_INVALID_HANDLE;\r
443       err:\r
444         ibv_free_device_list(dev_list);\r
445         return DAT_INTERNAL_ERROR;\r
446 }\r
447 \r
448 /*\r
449  * dapls_ib_close_hca\r
450  *\r
451  * Open HCA\r
452  *\r
453  * Input:\r
454  *      DAPL_HCA   provide CA handle\r
455  *\r
456  * Output:\r
457  *      none\r
458  *\r
459  * Return:\r
460  *      DAT_SUCCESS\r
461  *      dapl_convert_errno \r
462  *\r
463  */\r
464 DAT_RETURN dapls_ib_close_hca(IN DAPL_HCA * hca_ptr)\r
465 {\r
466         dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " close_hca: %p\n", hca_ptr);\r
467 \r
468         dapl_os_lock(&g_hca_lock);\r
469         if (g_ib_thread_state != IB_THREAD_RUN) {\r
470                 dapl_os_unlock(&g_hca_lock);\r
471                 goto out;\r
472         }\r
473         dapl_os_unlock(&g_hca_lock);\r
474 \r
475         /* destroy cr_thread and lock */\r
476         hca_ptr->ib_trans.cr_state = IB_THREAD_CANCEL;\r
477         send(hca_ptr->ib_trans.scm[1], "w", sizeof "w", 0);\r
478         while (hca_ptr->ib_trans.cr_state != IB_THREAD_EXIT) {\r
479                 dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
480                              " close_hca: waiting for cr_thread\n");\r
481                 send(hca_ptr->ib_trans.scm[1], "w", sizeof "w", 0);\r
482                 dapl_os_sleep_usec(1000);\r
483         }\r
484         dapl_os_lock_destroy(&hca_ptr->ib_trans.lock);\r
485         destroy_cr_pipe(hca_ptr); /* no longer need pipe */\r
486         \r
487         /* \r
488          * Remove hca from async event processing list\r
489          * Wakeup work thread to remove from polling list\r
490          */\r
491         hca_ptr->ib_trans.destroy = 1;\r
492         if (dapls_thread_signal() == -1)\r
493                 dapl_log(DAPL_DBG_TYPE_UTIL,\r
494                          " destroy: thread wakeup error = %s\n",\r
495                          strerror(errno));\r
496 \r
497         /* wait for thread to remove HCA references */\r
498         while (hca_ptr->ib_trans.destroy != 2) {\r
499                 if (dapls_thread_signal() == -1)\r
500                         dapl_log(DAPL_DBG_TYPE_UTIL,\r
501                                  " destroy: thread wakeup error = %s\n",\r
502                                  strerror(errno));\r
503                 dapl_os_sleep_usec(1000);\r
504         }\r
505 \r
506 out:\r
507         if (hca_ptr->ib_hca_handle != IB_INVALID_HANDLE) {\r
508                 if (ibv_close_device(hca_ptr->ib_hca_handle))\r
509                         return (dapl_convert_errno(errno, "ib_close_device"));\r
510                 hca_ptr->ib_hca_handle = IB_INVALID_HANDLE;\r
511         }\r
512         return (DAT_SUCCESS);\r
513 }\r
514 \r
515 DAT_RETURN dapli_ib_thread_init(void)\r
516 {\r
517         DAT_RETURN dat_status;\r
518 \r
519         dapl_os_lock(&g_hca_lock);\r
520         if (g_ib_thread_state != IB_THREAD_INIT) {\r
521                 dapl_os_unlock(&g_hca_lock);\r
522                 return DAT_SUCCESS;\r
523         }\r
524 \r
525         g_ib_thread_state = IB_THREAD_CREATE;\r
526         dapl_os_unlock(&g_hca_lock);\r
527 \r
528         /* create thread to process inbound connect request */\r
529         dat_status = dapl_os_thread_create(dapli_thread, NULL, &g_ib_thread);\r
530         if (dat_status != DAT_SUCCESS)\r
531                 return (dapl_convert_errno(errno,\r
532                                            "create_thread ERR:"\r
533                                            " check resource limits"));\r
534 \r
535         /* wait for thread to start */\r
536         dapl_os_lock(&g_hca_lock);\r
537         while (g_ib_thread_state != IB_THREAD_RUN) {\r
538                 dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
539                              " ib_thread_init: waiting for ib_thread\n");\r
540                 dapl_os_unlock(&g_hca_lock);\r
541                 dapl_os_sleep_usec(1000);\r
542                 dapl_os_lock(&g_hca_lock);\r
543         }\r
544         dapl_os_unlock(&g_hca_lock);\r
545 \r
546         return DAT_SUCCESS;\r
547 }\r
548 \r
549 void dapli_ib_thread_destroy(void)\r
550 {\r
551         dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
552                      " ib_thread_destroy(%d)\n", dapl_os_getpid());\r
553         /* \r
554          * wait for async thread to terminate. \r
555          * pthread_join would be the correct method\r
556          * but some applications have some issues\r
557          */\r
558 \r
559         /* destroy ib_thread, wait for termination, if not already */\r
560         dapl_os_lock(&g_hca_lock);\r
561         if (g_ib_thread_state != IB_THREAD_RUN)\r
562                 goto bail;\r
563 \r
564         g_ib_thread_state = IB_THREAD_CANCEL;\r
565         while (g_ib_thread_state != IB_THREAD_EXIT) {\r
566                 dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
567                              " ib_thread_destroy: waiting for ib_thread\n");\r
568                 if (dapls_thread_signal() == -1)\r
569                         dapl_log(DAPL_DBG_TYPE_UTIL,\r
570                                  " destroy: thread wakeup error = %s\n",\r
571                                  strerror(errno));\r
572                 dapl_os_unlock(&g_hca_lock);\r
573                 dapl_os_sleep_usec(2000);\r
574                 dapl_os_lock(&g_hca_lock);\r
575         }\r
576 bail:\r
577         dapl_os_unlock(&g_hca_lock);\r
578 \r
579         dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
580                      " ib_thread_destroy(%d) exit\n", dapl_os_getpid());\r
581 }\r
582 \r
583 \r
584 #if defined(_WIN64) || defined(_WIN32)\r
585 /* work thread for uAT, uCM, CQ, and async events */\r
586 void dapli_thread(void *arg)\r
587 {\r
588         struct _ib_hca_transport *hca;\r
589         struct _ib_hca_transport *uhca[8];\r
590         int ret, idx, cnt;\r
591 \r
592         dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d,0x%x): ENTER: \n",\r
593                      dapl_os_getpid(), g_ib_thread);\r
594 \r
595         dapl_os_lock(&g_hca_lock);\r
596         for (g_ib_thread_state = IB_THREAD_RUN;\r
597              g_ib_thread_state == IB_THREAD_RUN; \r
598              dapl_os_lock(&g_hca_lock)) {\r
599 \r
600                 CompSetZero(&ufds);\r
601                 idx = 0;\r
602                 hca = dapl_llist_is_empty(&g_hca_list) ? NULL :\r
603                       dapl_llist_peek_head(&g_hca_list);\r
604 \r
605                 while (hca) {\r
606                         CompSetAdd(&hca->ib_ctx->channel, &ufds);\r
607                         CompSetAdd(&hca->ib_cq->comp_channel, &ufds);\r
608                         uhca[idx++] = hca;\r
609                         hca = dapl_llist_next_entry(&g_hca_list,\r
610                                                     (DAPL_LLIST_ENTRY *)\r
611                                                     &hca->entry);\r
612                 }\r
613                 cnt = idx;\r
614 \r
615                 dapl_os_unlock(&g_hca_lock);\r
616                 ret = CompSetPoll(&ufds, INFINITE);\r
617 \r
618                 dapl_dbg_log(DAPL_DBG_TYPE_UTIL,\r
619                              " ib_thread(%d) poll_event 0x%x\n",\r
620                              dapl_os_getpid(), ret);\r
621 \r
622 \r
623                 /* check and process ASYNC events, per device */\r
624                 for (idx = 0; idx < cnt; idx++) {\r
625                         if (uhca[idx]->destroy == 1) {\r
626                                 dapl_os_lock(&g_hca_lock);\r
627                                 dapl_llist_remove_entry(&g_hca_list,\r
628                                                         (DAPL_LLIST_ENTRY *)\r
629                                                         &uhca[idx]->entry);\r
630                                 dapl_os_unlock(&g_hca_lock);\r
631                                 uhca[idx]->destroy = 2;\r
632                         } else {\r
633                                 dapli_cq_event_cb(uhca[idx]);\r
634                                 dapli_async_event_cb(uhca[idx]);\r
635                         }\r
636                 }\r
637         }\r
638 \r
639         dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " ib_thread(%d) EXIT\n",\r
640                      dapl_os_getpid());\r
641         g_ib_thread_state = IB_THREAD_EXIT;\r
642         dapl_os_unlock(&g_hca_lock);\r
643 }\r
644 #else                           // _WIN64 || WIN32\r
645 \r
646 /* work thread for uAT, uCM, CQ, and async events */\r
647 void dapli_thread(void *arg)\r
648 {\r
649         struct pollfd ufds[__FD_SETSIZE];\r
650         struct _ib_hca_transport *uhca[__FD_SETSIZE] = { NULL };\r
651         struct _ib_hca_transport *hca;\r
652         int ret, idx, fds;\r
653         char rbuf[2];\r
654 \r
655         dapl_dbg_log(DAPL_DBG_TYPE_THREAD,\r
656                      " ib_thread(%d,0x%x): ENTER: pipe %d \n",\r
657                      dapl_os_getpid(), g_ib_thread, g_ib_pipe[0]);\r
658 \r
659         /* Poll across pipe, CM, AT never changes */\r
660         dapl_os_lock(&g_hca_lock);\r
661         g_ib_thread_state = IB_THREAD_RUN;\r
662 \r
663         ufds[0].fd = g_ib_pipe[0];      /* pipe */\r
664         ufds[0].events = POLLIN;\r
665 \r
666         while (g_ib_thread_state == IB_THREAD_RUN) {\r
667 \r
668                 /* build ufds after pipe and uCMA events */\r
669                 ufds[0].revents = 0;\r
670                 idx = 0;\r
671 \r
672                 /*  Walk HCA list and setup async and CQ events */\r
673                 if (!dapl_llist_is_empty(&g_hca_list))\r
674                         hca = dapl_llist_peek_head(&g_hca_list);\r
675                 else\r
676                         hca = NULL;\r
677 \r
678                 while (hca) {\r
679 \r
680                         /* uASYNC events */\r
681                         ufds[++idx].fd = hca->ib_ctx->async_fd;\r
682                         ufds[idx].events = POLLIN;\r
683                         ufds[idx].revents = 0;\r
684                         uhca[idx] = hca;\r
685 \r
686                         /* CQ events are non-direct with CNO's */\r
687                         ufds[++idx].fd = hca->ib_cq->fd;\r
688                         ufds[idx].events = POLLIN;\r
689                         ufds[idx].revents = 0;\r
690                         uhca[idx] = hca;\r
691 \r
692                         dapl_dbg_log(DAPL_DBG_TYPE_THREAD,\r
693                                      " ib_thread(%d) poll_fd: hca[%d]=%p,"\r
694                                      " async=%d pipe=%d \n",\r
695                                      dapl_os_getpid(), hca, ufds[idx - 1].fd,\r
696                                      ufds[0].fd);\r
697 \r
698                         hca = dapl_llist_next_entry(&g_hca_list,\r
699                                                     (DAPL_LLIST_ENTRY *)\r
700                                                     &hca->entry);\r
701                 }\r
702 \r
703                 /* unlock, and setup poll */\r
704                 fds = idx + 1;\r
705                 dapl_os_unlock(&g_hca_lock);\r
706                 ret = poll(ufds, fds, -1);\r
707                 if (ret <= 0) {\r
708                         dapl_dbg_log(DAPL_DBG_TYPE_THREAD,\r
709                                      " ib_thread(%d): ERR %s poll\n",\r
710                                      dapl_os_getpid(), strerror(errno));\r
711                         dapl_os_lock(&g_hca_lock);\r
712                         continue;\r
713                 }\r
714 \r
715                 dapl_dbg_log(DAPL_DBG_TYPE_THREAD,\r
716                              " ib_thread(%d) poll_event: "\r
717                              " async=0x%x pipe=0x%x \n",\r
718                              dapl_os_getpid(), ufds[idx].revents,\r
719                              ufds[0].revents);\r
720 \r
721                 /* check and process CQ and ASYNC events, per device */\r
722                 for (idx = 1; idx < fds; idx++) {\r
723                         if (ufds[idx].revents == POLLIN) {\r
724                                 dapli_cq_event_cb(uhca[idx]);\r
725                                 dapli_async_event_cb(uhca[idx]);\r
726                         }\r
727                 }\r
728 \r
729                 /* check and process user events, PIPE */\r
730                 if (ufds[0].revents == POLLIN) {\r
731                         if (read(g_ib_pipe[0], rbuf, 2) == -1)\r
732                                 dapl_log(DAPL_DBG_TYPE_THREAD,\r
733                                          " cr_thread: pipe rd err= %s\n",\r
734                                          strerror(errno));\r
735 \r
736                         /* cleanup any device on list marked for destroy */\r
737                         for (idx = 1; idx < fds; idx++) {\r
738                                 if (uhca[idx] && uhca[idx]->destroy == 1) {\r
739                                         dapl_os_lock(&g_hca_lock);\r
740                                         dapl_llist_remove_entry(\r
741                                                 &g_hca_list,\r
742                                                 (DAPL_LLIST_ENTRY*)\r
743                                                 &uhca[idx]->entry);\r
744                                         dapl_os_unlock(&g_hca_lock);\r
745                                         uhca[idx]->destroy = 2;\r
746                                 }\r
747                         }\r
748                 }\r
749                 dapl_os_lock(&g_hca_lock);\r
750         }\r
751 \r
752         dapl_dbg_log(DAPL_DBG_TYPE_THREAD, " ib_thread(%d) EXIT\n",\r
753                      dapl_os_getpid());\r
754         g_ib_thread_state = IB_THREAD_EXIT;\r
755         dapl_os_unlock(&g_hca_lock);\r
756 }\r
757 #endif\r