1 /*
2 * Copyright (c) 2015-2017 Los Alamos National Security, LLC.
3 * All rights reserved.
4 * Copyright (c) 2015-2017 Cray Inc. All rights reserved.
5 *
6 * This software is available to you under a choice of one of two
7 * licenses. You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * BSD license below:
11 *
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
15 *
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer.
19 *
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials
23 * provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <errno.h>
38 #include <getopt.h>
39 #include <poll.h>
40 #include <time.h>
41 #include <string.h>
42
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <inttypes.h>
47
48 #include "gnix_cq.h"
49 #include "gnix.h"
50
51 #include <criterion/criterion.h>
52 #include "gnix_rdma_headers.h"
53 #include "common.h"
54
55 /* Note: Set to ~FI_NOTIFY_FLAGS_ONLY since this was written before api 1.5 */
56 static uint64_t mode_bits = ~FI_NOTIFY_FLAGS_ONLY;
57 static uint64_t old_mode_bits;
58 static struct fid_fabric *fab;
59 static struct fid_domain *dom;
60 static struct gnix_fid_ep *ep;
61 static struct fid_ep *fid_ep;
62 static struct fid_cq *rcq;
63 static struct fi_info *hints;
64 static struct fi_info *fi;
65 static struct fi_cq_attr cq_attr;
66 static struct gnix_fid_cq *cq_priv;
67
68 static struct gnix_fid_wait *wait_priv;
69 static struct fid_wait *wait_set;
70 static struct fi_wait_attr wait_attr;
71
_setup(uint32_t version)72 static void _setup(uint32_t version)
73 {
74 int ret = 0;
75
76 hints = fi_allocinfo();
77 cr_assert(hints, "fi_allocinfo");
78 if (FI_VERSION_LT(version, FI_VERSION(1, 5)))
79 hints->domain_attr->mr_mode = FI_MR_BASIC;
80 else
81 hints->domain_attr->mr_mode = GNIX_DEFAULT_MR_MODE;
82 hints->domain_attr->cq_data_size = 4;
83 hints->mode = mode_bits;
84
85 hints->fabric_attr->prov_name = strdup("gni");
86
87 ret = fi_getinfo(version, NULL, 0, 0, hints, &fi);
88 cr_assert(!ret, "fi_getinfo");
89
90 ret = fi_fabric(fi->fabric_attr, &fab, NULL);
91 cr_assert(!ret, "fi_fabric");
92
93 ret = fi_domain(fab, fi, &dom, NULL);
94 cr_assert(!ret, "fi_domain");
95
96 cq_attr.wait_obj = FI_WAIT_NONE;
97 }
98
setup(void)99 static void setup(void)
100 {
101 _setup(fi_version());
102 }
103
setup_1_4(void)104 static void setup_1_4(void)
105 {
106 _setup(FI_VERSION(1, 4));
107 }
108
teardown(void)109 static void teardown(void)
110 {
111 int ret = 0;
112
113 ret = fi_close(&dom->fid);
114 cr_assert(!ret, "failure in closing domain.");
115 ret = fi_close(&fab->fid);
116 cr_assert(!ret, "failure in closing fabric.");
117 fi_freeinfo(fi);
118 fi_freeinfo(hints);
119 }
120
cq_create(enum fi_cq_format format,enum fi_wait_obj wait_obj,size_t size)121 void cq_create(enum fi_cq_format format, enum fi_wait_obj wait_obj,
122 size_t size)
123 {
124 int ret = 0;
125
126 cq_attr.format = format;
127 cq_attr.size = size;
128 cq_attr.wait_obj = wait_obj;
129
130 ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
131 cr_assert(!ret, "fi_cq_open");
132
133 cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
134
135 if (cq_priv->wait) {
136 wait_priv = container_of(cq_priv->wait, struct gnix_fid_wait,
137 wait);
138 }
139 }
140
cq_setup(void)141 void cq_setup(void)
142 {
143 setup();
144 cq_create(FI_CQ_FORMAT_UNSPEC, FI_WAIT_NONE, 0);
145 }
146
cq_setup_1_4(void)147 void cq_setup_1_4(void)
148 {
149 setup_1_4();
150 cq_create(FI_CQ_FORMAT_UNSPEC, FI_WAIT_NONE, 0);
151 }
152
cq_msg_setup(void)153 void cq_msg_setup(void)
154 {
155 setup();
156 cq_create(FI_CQ_FORMAT_MSG, FI_WAIT_NONE, 8);
157 }
158
cq_data_setup(void)159 void cq_data_setup(void)
160 {
161 setup();
162 cq_create(FI_CQ_FORMAT_DATA, FI_WAIT_NONE, 8);
163 }
164
cq_tagged_setup(void)165 void cq_tagged_setup(void)
166 {
167 setup();
168 cq_create(FI_CQ_FORMAT_TAGGED, FI_WAIT_NONE, 8);
169 }
170
cq_wait_none_setup(void)171 void cq_wait_none_setup(void)
172 {
173 setup();
174 cq_create(FI_CQ_FORMAT_MSG, FI_WAIT_NONE, 8);
175 }
176
cq_wait_fd_setup(void)177 void cq_wait_fd_setup(void)
178 {
179 setup();
180 cq_create(FI_CQ_FORMAT_MSG, FI_WAIT_FD, 8);
181 }
182
cq_wait_unspec_setup(void)183 void cq_wait_unspec_setup(void)
184 {
185 setup();
186 cq_create(FI_CQ_FORMAT_MSG, FI_WAIT_UNSPEC, 8);
187 }
188
cq_wait_mutex_cond_setup(void)189 void cq_wait_mutex_cond_setup(void)
190 {
191 setup();
192 cq_create(FI_CQ_FORMAT_MSG, FI_WAIT_MUTEX_COND, 8);
193 }
194
cq_notify_setup(void)195 void cq_notify_setup(void)
196 {
197 int ret;
198 old_mode_bits = mode_bits;
199 mode_bits = FI_NOTIFY_FLAGS_ONLY;
200 setup();
201
202 ret = fi_endpoint(dom, fi, &fid_ep, NULL);
203 cr_assert(!ret, "fi_endpoint");
204 cr_assert(fid_ep != NULL);
205
206 ep = container_of(fid_ep, struct gnix_fid_ep, ep_fid);
207 cr_assert(ep, "ep not allocated");
208
209 cq_create(FI_CQ_FORMAT_MSG, FI_WAIT_NONE, 0);
210 }
211
cq_teardown(void)212 void cq_teardown(void)
213 {
214 cr_assert(!fi_close(&rcq->fid), "failure in closing cq.");
215 teardown();
216 }
217
cq_notify_teardown(void)218 void cq_notify_teardown(void)
219 {
220 cr_assert(!fi_close(&rcq->fid), "failure in closing cq.");
221 cr_assert(!fi_close(&fid_ep->fid), "failure in closing ep.");
222 teardown();
223 mode_bits = old_mode_bits;
224
225 }
226
227 /*******************************************************************************
228 * Creation Tests:
229 *
230 * Create the CQ with various parameters and make sure the fields are being
231 * initialized correctly.
232 ******************************************************************************/
233
234 TestSuite(creation, .init = setup, .fini = cq_teardown);
235
Test(creation,format_unspec)236 Test(creation, format_unspec)
237 {
238 int ret = 0;
239
240 cq_attr.format = FI_CQ_FORMAT_UNSPEC;
241
242 ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
243 cr_assert(!ret, "fi_cq_open");
244
245 cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
246 cr_assert(cq_priv->entry_size == sizeof(struct fi_cq_entry));
247 }
248
Test(creation,format_context)249 Test(creation, format_context)
250 {
251 int ret = 0;
252
253 cq_attr.format = FI_CQ_FORMAT_CONTEXT;
254
255 ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
256 cr_assert(!ret, "fi_cq_open");
257
258 cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
259 cr_assert(cq_priv->entry_size == sizeof(struct fi_cq_entry));
260 }
261
Test(creation,format_msg)262 Test(creation, format_msg)
263 {
264 int ret = 0;
265
266 cq_attr.format = FI_CQ_FORMAT_MSG;
267
268 ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
269 cr_assert(!ret, "fi_cq_open");
270
271 cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
272 cr_assert(cq_priv->entry_size == sizeof(struct fi_cq_msg_entry));
273 }
274
Test(creation,format_data)275 Test(creation, format_data)
276 {
277 int ret = 0;
278
279 cq_attr.format = FI_CQ_FORMAT_DATA;
280
281 ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
282 cr_assert(!ret, "fi_cq_open");
283
284 cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
285 cr_assert(cq_priv->entry_size == sizeof(struct fi_cq_data_entry));
286 }
287
Test(creation,format_tagged)288 Test(creation, format_tagged)
289 {
290 int ret = 0;
291
292 cq_attr.format = FI_CQ_FORMAT_TAGGED;
293
294 ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
295 cr_assert(!ret, "fi_cq_open");
296
297 cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
298 cr_assert(cq_priv->entry_size == sizeof(struct fi_cq_tagged_entry));
299 }
300
301 TestSuite(insertion, .init = cq_setup, .fini = cq_teardown);
302
Test(insertion,single)303 Test(insertion, single)
304 {
305 int ret = 0;
306 char input_ctx = 'a';
307 struct fi_cq_entry entry;
308
309 cr_assert(!cq_priv->events->item_list.head);
310
311 _gnix_cq_add_event(cq_priv, NULL, &input_ctx, 0, 0, 0, 0, 0, 0);
312
313 cr_assert(cq_priv->events->item_list.head);
314 cr_assert_eq(cq_priv->events->item_list.head,
315 cq_priv->events->item_list.tail);
316
317 ret = fi_cq_read(rcq, &entry, 1);
318 cr_assert(ret == 1);
319 cr_assert(!cq_priv->events->item_list.head);
320
321 cr_assert_eq(*(char *) entry.op_context, input_ctx,
322 "Expected same op_context as inserted.");
323 }
324
Test(insertion,limit)325 Test(insertion, limit)
326 {
327 int ret = 0;
328 char input_ctx = 'a';
329 struct fi_cq_entry entry;
330 const size_t cq_size = cq_priv->attr.size;
331
332 for (size_t i = 0; i < cq_size; i++)
333 _gnix_cq_add_event(cq_priv, NULL, &input_ctx, 0, 0, 0, 0, 0, 0);
334
335 cr_assert(cq_priv->events->item_list.head);
336 cr_assert(!cq_priv->events->free_list.head);
337
338 _gnix_cq_add_event(cq_priv, NULL, &input_ctx, 0, 0, 0, 0, 0, 0);
339
340 for (size_t i = 0; i < cq_size + 1; i++) {
341 ret = fi_cq_read(rcq, &entry, 1);
342 cr_assert_eq(ret, 1);
343 }
344
345 cr_assert(!cq_priv->events->item_list.head);
346 cr_assert(cq_priv->events->free_list.head);
347 }
348
349 TestSuite(mode_bits, .init = NULL, .fini = teardown);
350
Test(mode_bits,fi_notify_flags_only_1_4)351 Test(mode_bits, fi_notify_flags_only_1_4)
352 {
353 old_mode_bits = mode_bits;
354 mode_bits = ~0;
355 _setup(FI_VERSION(1, 4));
356 cr_assert_eq(fi->mode & FI_NOTIFY_FLAGS_ONLY, 0, "Did not clear notify flag for version 1.4");
357 mode_bits = old_mode_bits;
358 }
359
Test(mode_bits,fi_notify_flags_only)360 Test(mode_bits, fi_notify_flags_only)
361 {
362 old_mode_bits = mode_bits;
363 mode_bits = ~0;
364 _setup(fi_version());
365 cr_assert(fi->mode & FI_NOTIFY_FLAGS_ONLY, "Cleared the notify flag when we shouldn't have\n");
366 mode_bits = old_mode_bits;
367 }
368
369 TestSuite(reading, .init = cq_setup, .fini = cq_teardown);
370
Test(reading,empty)371 Test(reading, empty)
372 {
373 int ret = 0;
374 struct fi_cq_entry entry;
375
376 ret = fi_cq_read(rcq, &entry, 1);
377 cr_assert_eq(ret, -FI_EAGAIN);
378 }
379
Test(reading,error)380 Test(reading, error)
381 {
382 int ret = 0;
383 struct fi_cq_entry entry;
384 struct fi_cq_err_entry err_entry;
385
386 char input_ctx = 'a';
387 uint64_t flags = 0xb;
388 size_t len = sizeof(input_ctx);
389 void *buf = &input_ctx;
390 uint64_t data = 20;
391 uint64_t tag = 40;
392 size_t olen = 20;
393 int err = 50;
394 int prov_errno = 80;
395
396 /*
397 * By default CQ start out with no error entries and no entries
398 * in the error entry free list.
399 */
400 cr_assert(!cq_priv->errors->item_list.head);
401 cr_assert(!cq_priv->errors->free_list.head);
402
403 _gnix_cq_add_error(cq_priv, &input_ctx, flags, len, buf, data, tag,
404 olen, err, prov_errno, 0, 0);
405
406 cr_assert(cq_priv->errors->item_list.head);
407
408 ret = fi_cq_read(rcq, &entry, 1);
409 cr_assert_eq(ret, -FI_EAVAIL);
410
411 cr_assert(!cq_priv->events->item_list.head);
412 cr_assert(cq_priv->errors->item_list.head);
413 /* Testing err_data == NULL path set size to something
414 * other than 0 then verify it was set back to 0 */
415 err_entry.err_data_size = 12;
416 err_entry.err_data = malloc(12);
417 ret = fi_cq_readerr(rcq, &err_entry, 0);
418 cr_assert_eq(ret, 1);
419
420 /*
421 * Item should have been removed from error queue and placed on free
422 * queue.
423 */
424 cr_assert(!cq_priv->errors->item_list.head);
425 cr_assert(cq_priv->errors->free_list.head);
426
427 /*
428 * Compare structural items...
429 */
430 cr_assert_eq(*(char *) err_entry.op_context, input_ctx);
431 cr_assert_eq(err_entry.flags, flags);
432 cr_assert_eq(err_entry.len, len);
433 cr_assert_eq(err_entry.buf, buf);
434 cr_assert_eq(err_entry.data, data);
435 cr_assert_eq(err_entry.tag, tag);
436 cr_assert_eq(err_entry.olen, olen);
437 cr_assert_eq(err_entry.err, err);
438 cr_assert_eq(err_entry.prov_errno, prov_errno);
439 cr_assert(err_entry.err_data != NULL);
440 free(err_entry.err_data);
441 cr_assert(err_entry.err_data_size == 0);
442 }
443
444 TestSuite(reading_1_4, .init = cq_setup_1_4, .fini = cq_teardown);
445
Test(reading_1_4,error)446 Test(reading_1_4, error)
447 {
448 int ret = 0;
449 struct fi_cq_entry entry;
450 struct fi_cq_err_entry err_entry;
451
452 char input_ctx = 'a';
453 uint64_t flags = 0xb;
454 size_t len = sizeof(input_ctx);
455 void *buf = &input_ctx;
456 uint64_t data = 20;
457 uint64_t tag = 40;
458 size_t olen = 20;
459 int err = 50;
460 int prov_errno = 80;
461
462 /*
463 * By default CQ start out with no error entries and no entries
464 * in the error entry free list.
465 */
466 cr_assert(!cq_priv->errors->item_list.head);
467 cr_assert(!cq_priv->errors->free_list.head);
468
469 _gnix_cq_add_error(cq_priv, &input_ctx, flags, len, buf, data, tag,
470 olen, err, prov_errno, 0, 0);
471
472 cr_assert(cq_priv->errors->item_list.head);
473
474 ret = fi_cq_read(rcq, &entry, 1);
475 cr_assert_eq(ret, -FI_EAVAIL);
476
477 cr_assert(!cq_priv->events->item_list.head);
478 cr_assert(cq_priv->errors->item_list.head);
479 ret = fi_cq_readerr(rcq, &err_entry, 0);
480 cr_assert_eq(ret, 1);
481
482 /*
483 * Item should have been removed from error queue and placed on free
484 * queue.
485 */
486 cr_assert(!cq_priv->errors->item_list.head);
487 cr_assert(cq_priv->errors->free_list.head);
488
489 /*
490 * Compare structural items...
491 */
492 cr_assert_eq(*(char *) err_entry.op_context, input_ctx);
493 cr_assert_eq(err_entry.flags, flags);
494 cr_assert_eq(err_entry.len, len);
495 cr_assert_eq(err_entry.buf, buf);
496 cr_assert_eq(err_entry.data, data);
497 cr_assert_eq(err_entry.tag, tag);
498 cr_assert_eq(err_entry.olen, olen);
499 cr_assert_eq(err_entry.err, err);
500 cr_assert_eq(err_entry.prov_errno, prov_errno);
501 cr_assert(err_entry.err_data == NULL);
502 }
503
504 #define ENTRY_CNT 5
Test(reading,issue192)505 Test(reading, issue192)
506 {
507 int ret = 0;
508 char input_ctx = 'a';
509 struct fi_cq_entry entries[ENTRY_CNT];
510
511 _gnix_cq_add_event(cq_priv, NULL, &input_ctx, 0, 0, 0, 0, 0, 0);
512
513 ret = fi_cq_read(rcq, &entries, ENTRY_CNT);
514 cr_assert_eq(ret, 1);
515
516 ret = fi_cq_read(rcq, &entries, ENTRY_CNT);
517 cr_assert_eq(ret, -FI_EAGAIN);
518 }
519
520
cq_add_read_setup(enum fi_cq_format format)521 static void cq_add_read_setup(enum fi_cq_format format)
522 {
523 switch (format) {
524 default:
525 case FI_CQ_FORMAT_UNSPEC:
526 cq_setup();
527 break;
528 case FI_CQ_FORMAT_MSG:
529 cq_msg_setup();
530 break;
531 case FI_CQ_FORMAT_DATA:
532 cq_data_setup();
533 break;
534 case FI_CQ_FORMAT_TAGGED:
535 cq_tagged_setup();
536 break;
537 }
538 }
539
cq_add_read_check(enum fi_cq_format format,struct fi_cq_tagged_entry * entry,struct fi_cq_tagged_entry * expected)540 static void cq_add_read_check(enum fi_cq_format format,
541 struct fi_cq_tagged_entry *entry,
542 struct fi_cq_tagged_entry *expected)
543 {
544 cr_assert_eq(*(char *) entry->op_context,
545 *(char *) expected->op_context);
546
547 if (format == FI_CQ_FORMAT_UNSPEC ||
548 format == FI_CQ_FORMAT_CONTEXT) {
549 return;
550 }
551
552 cr_assert_eq(entry->flags, expected->flags);
553 cr_assert_eq(entry->len, expected->len);
554
555 if (format == FI_CQ_FORMAT_MSG) {
556 return;
557 }
558
559 cr_assert_eq(entry->buf, expected->buf);
560 cr_assert_eq(entry->data, expected->data);
561
562 if (format == FI_CQ_FORMAT_DATA) {
563 return;
564 }
565
566 cr_assert_eq(entry->tag, expected->tag);
567 }
568
569 /*
570 * Add an event and read the cq.
571 */
cq_add_read(enum fi_cq_format format)572 static void cq_add_read(enum fi_cq_format format)
573 {
574 int ret = 0;
575 char input_ctx = 'a';
576 struct fi_cq_tagged_entry entry; /* biggest one */
577 struct fi_cq_tagged_entry expected = { &input_ctx, 2, 4, (void *) 8,
578 16, 32 };
579
580 cq_add_read_setup(format);
581
582 cr_assert(!cq_priv->events->item_list.head);
583
584 _gnix_cq_add_event(cq_priv, NULL, expected.op_context, expected.flags,
585 expected.len, expected.buf, expected.data,
586 expected.tag, 0x0);
587
588 cr_assert(cq_priv->events->item_list.head);
589
590 ret = fi_cq_read(rcq, &entry, 1);
591 cr_assert_eq(ret, 1);
592
593 cq_add_read_check(format, &entry, &expected);
594
595 cr_assert(!cq_priv->events->item_list.head);
596 }
597
598 /*
599 * Create up to the size events to fill it up. Check that all the properties
600 * are correct, then add one more that is different. Read size items and then
601 * add an error and try reading. Ensure that we get back -FI_EAVAIL. Then read
602 * the last item and make sure it's the same values put in originally.
603 */
cq_fill_test(enum fi_cq_format format)604 static void cq_fill_test(enum fi_cq_format format)
605 {
606 char input_ctx = 'a';
607 struct fi_cq_tagged_entry entry; /* biggest one */
608 struct fi_cq_tagged_entry expected = { &input_ctx, 2, 4, (void *) 8,
609 16, 32 };
610 struct fi_cq_err_entry err_entry;
611 int ret = 0;
612 uint64_t flags = 2;
613 size_t len = 4;
614 size_t cq_size;
615
616 cq_add_read_setup(format);
617
618 cr_assert(!cq_priv->events->item_list.head);
619 cr_assert(cq_priv->events->free_list.head);
620
621 cq_size = cq_priv->attr.size;
622 for (size_t i = 0; i < cq_size; i++) {
623 _gnix_cq_add_event(cq_priv, NULL, expected.op_context,
624 expected.flags, expected.len,
625 expected.buf, expected.data,
626 expected.tag, 0x0);
627 }
628
629 cr_assert(cq_priv->events->item_list.head);
630 cr_assert(!cq_priv->events->free_list.head);
631
632 _gnix_cq_add_event(cq_priv, NULL, expected.op_context,
633 expected.flags, 2 * expected.len, expected.buf,
634 expected.data, expected.tag, 0x0);
635
636 for (size_t i = 0; i < cq_size; i++) {
637 ret = fi_cq_read(rcq, &entry, 1);
638 cr_assert_eq(ret, 1);
639 cq_add_read_check(format, &entry, &expected);
640 }
641
642 /*
643 * If we insert an error it should return -FI_EAVAIL despite having
644 * something to read.
645 */
646
647 _gnix_cq_add_error(cq_priv, &input_ctx, flags, len, 0, 0, 0, 0, 0, 0,
648 0, 0);
649 cr_assert(cq_priv->errors->item_list.head);
650
651 ret = fi_cq_read(rcq, &entry, 1);
652 cr_assert_eq(ret, -FI_EAVAIL);
653
654 ret = fi_cq_readerr(rcq, &err_entry, 0);
655 cr_assert_eq(ret, 1);
656
657 /*
658 * Creating an error allocs an error but it is then placed in the free
659 * list after reading.
660 */
661 cr_assert(cq_priv->errors->free_list.head);
662 cr_assert(!cq_priv->errors->item_list.head);
663
664 ret = fi_cq_read(rcq, &entry, 1);
665 cr_assert_eq(ret, 1);
666
667 cr_assert(cq_priv->events->free_list.head);
668 cr_assert(!cq_priv->events->item_list.head);
669
670 expected.len *= 2;
671 cq_add_read_check(format, &entry, &expected);
672 }
673
674 /*
675 * Read more than one cqe at a time.
676 */
cq_multi_read_test(enum fi_cq_format format)677 static void cq_multi_read_test(enum fi_cq_format format)
678 {
679 int ret = 0;
680 size_t count = 3;
681 char input_ctx = 'a';
682 struct fi_cq_tagged_entry entry[count]; /* biggest one */
683 struct fi_cq_tagged_entry expected = { &input_ctx, 2, 4, (void *) 8,
684 16, 32 };
685
686 cq_add_read_setup(format);
687
688 cr_assert(cq_priv->events->free_list.head);
689 cr_assert(!cq_priv->events->item_list.head);
690
691 for (size_t i = 0; i < count; i++) {
692 _gnix_cq_add_event(cq_priv, NULL, expected.op_context,
693 expected.flags, expected.len,
694 expected.buf, expected.data,
695 expected.tag, 0x0);
696 }
697
698 cr_assert(cq_priv->events->item_list.head);
699
700 ret = fi_cq_read(rcq, &entry, count);
701 cr_assert_eq(ret, count);
702
703 for (size_t j = 0; j < count; j++) {
704 /* This is gross */
705 switch (format) {
706 default:
707 case FI_CQ_FORMAT_UNSPEC:
708 {
709 struct fi_cq_entry *e = (struct fi_cq_entry *) entry;
710
711 cq_add_read_check(format,
712 (struct fi_cq_tagged_entry *) &e[j],
713 &expected);
714 break;
715 }
716 case FI_CQ_FORMAT_MSG:
717 {
718 struct fi_cq_msg_entry *e =
719 (struct fi_cq_msg_entry *) entry;
720
721 cq_add_read_check(format,
722 (struct fi_cq_tagged_entry *) &e[j],
723 &expected);
724 break;
725 }
726 case FI_CQ_FORMAT_DATA:
727 {
728 struct fi_cq_data_entry *e =
729 (struct fi_cq_data_entry *) entry;
730
731 cq_add_read_check(format,
732 (struct fi_cq_tagged_entry *) &e[j],
733 &expected);
734 break;
735 }
736 case FI_CQ_FORMAT_TAGGED:
737 {
738 cq_add_read_check(format, &entry[j], &expected);
739 break;
740 }
741 }
742 }
743 }
744
745 TestSuite(check_cqe, .init = NULL, .fini = cq_teardown);
746
Test(check_cqe,context)747 Test(check_cqe, context) {
748 cq_add_read(FI_CQ_FORMAT_CONTEXT);
749 }
750
Test(check_cqe,context_fill)751 Test(check_cqe, context_fill) {
752 cq_fill_test(FI_CQ_FORMAT_CONTEXT);
753 }
754
Test(check_cqe,context_multi_read)755 Test(check_cqe, context_multi_read) {
756 cq_multi_read_test(FI_CQ_FORMAT_CONTEXT);
757 }
758
Test(check_cqe,msg)759 Test(check_cqe, msg) {
760 cq_add_read(FI_CQ_FORMAT_MSG);
761 }
762
Test(check_cqe,msg_fill)763 Test(check_cqe, msg_fill) {
764 cq_fill_test(FI_CQ_FORMAT_MSG);
765 }
766
Test(check_cqe,msg_multi_read)767 Test(check_cqe, msg_multi_read) {
768 cq_multi_read_test(FI_CQ_FORMAT_MSG);
769 }
770
Test(check_cqe,data)771 Test(check_cqe, data) {
772 cq_add_read(FI_CQ_FORMAT_DATA);
773 }
774
Test(check_cqe,data_fill)775 Test(check_cqe, data_fill) {
776 cq_fill_test(FI_CQ_FORMAT_DATA);
777 }
778
Test(check_cqe,data_multi_read)779 Test(check_cqe, data_multi_read) {
780 cq_multi_read_test(FI_CQ_FORMAT_DATA);
781 }
782
Test(check_cqe,tagged)783 Test(check_cqe, tagged) {
784 cq_add_read(FI_CQ_FORMAT_TAGGED);
785 }
786
Test(check_cqe,tagged_fill)787 Test(check_cqe, tagged_fill) {
788 cq_fill_test(FI_CQ_FORMAT_TAGGED);
789 }
790
Test(check_cqe,tagged_multi_read)791 Test(check_cqe, tagged_multi_read) {
792 cq_multi_read_test(FI_CQ_FORMAT_TAGGED);
793 }
794
795 /* This test should be combined with cq_multi_read_test above when
796 * wait object are implemented.
797 */
798 Test(cq_msg, multi_sread, .init = cq_wait_unspec_setup, .disabled = false)
799 {
800 int ret = 0;
801 size_t count = 3;
802 struct fi_cq_msg_entry entry[count];
803
804 cr_assert(cq_priv->events->free_list.head);
805 cr_assert(!cq_priv->events->item_list.head);
806
807 ret = fi_cq_sread(rcq, &entry, count, NULL, 100);
808 cr_assert_eq(ret, -FI_EAGAIN);
809
810 for (size_t i = 0; i < count; i++)
811 _gnix_cq_add_event(cq_priv, NULL, 0, (uint64_t) i, 0, 0, 0, 0, 0);
812
813 cr_assert(cq_priv->events->item_list.head);
814
815 ret = fi_cq_sread(rcq, &entry, count, NULL, -1);
816 cr_assert_eq(ret, count);
817
818 for (size_t j = 0; j < count; j++)
819 cr_assert_eq(entry[j].flags, (uint64_t) j);
820 }
821
822 TestSuite(cq_wait_obj, .fini = cq_teardown);
823 TestSuite(cq_wait_control, .fini = cq_teardown, .disabled = true);
824 TestSuite(cq_wait_ops, .fini = cq_teardown);
825
826 Test(cq_wait_obj, none, .init = cq_wait_none_setup)
827 {
828 cr_expect(!wait_priv, "wait_priv is not null.");
829 }
830
831 Test(cq_wait_obj, unspec, .init = cq_wait_unspec_setup)
832 {
833 cr_expect_eq(wait_priv->type, FI_WAIT_UNSPEC);
834 cr_expect_eq(wait_priv->type, cq_priv->attr.wait_obj);
835 cr_expect_eq(wait_priv->type, cq_attr.wait_obj);
836 cr_expect_eq(&wait_priv->fabric->fab_fid, fab);
837 cr_expect_eq(wait_priv->cond_type, FI_CQ_COND_NONE);
838 }
839
840 Test(cq_wait_obj, fd, .init = cq_wait_fd_setup, .disabled = true)
841 {
842 cr_expect_eq(wait_priv->type, FI_WAIT_FD);
843 cr_expect_eq(wait_priv->type, cq_priv->attr.wait_obj);
844 cr_expect_eq(wait_priv->type, cq_attr.wait_obj);
845 cr_expect_eq(&wait_priv->fabric->fab_fid, fab);
846 cr_expect_eq(wait_priv->cond_type, FI_CQ_COND_NONE);
847 }
848
849 Test(cq_wait_obj, mutex_cond, .init = cq_wait_mutex_cond_setup, .disabled = true)
850 {
851 cr_expect_eq(wait_priv->type, FI_WAIT_MUTEX_COND);
852 cr_expect_eq(wait_priv->type, cq_priv->attr.wait_obj);
853 cr_expect_eq(wait_priv->type, cq_attr.wait_obj);
854 cr_expect_eq(&wait_priv->fabric->fab_fid, fab);
855 cr_expect_eq(wait_priv->cond_type, FI_CQ_COND_NONE);
856 }
857
858 Test(cq_wait_control, none, .init = cq_wait_none_setup)
859 {
860 int ret;
861 int fd;
862
863 ret = fi_control(&cq_priv->cq_fid.fid, FI_GETWAIT, &fd);
864 cr_expect_eq(-FI_ENOSYS, ret, "fi_control exists for none.");
865 }
866
867 Test(cq_wait_control, unspec, .init = cq_wait_unspec_setup, .disabled = true)
868 {
869 int ret;
870 int fd;
871
872 ret = fi_control(&cq_priv->cq_fid.fid, FI_GETWAIT, &fd);
873 cr_expect_eq(FI_SUCCESS, ret, "fi_control failed.");
874
875 cr_expect_eq(wait_priv->fd[WAIT_READ], fd);
876 }
877
878 Test(cq_wait_control, fd, .init = cq_wait_fd_setup,
879 .disabled = true)
880 {
881 int ret;
882 int fd;
883
884 ret = fi_control(&cq_priv->cq_fid.fid, FI_GETWAIT, &fd);
885 cr_expect_eq(FI_SUCCESS, ret, "fi_control failed.");
886
887 cr_expect_eq(wait_priv->fd[WAIT_READ], fd);
888 }
889
890 Test(cq_wait_control, mutex_cond, .init = cq_wait_mutex_cond_setup,
891 .disabled = true)
892 {
893 int ret;
894 struct fi_mutex_cond mutex_cond;
895
896 ret = fi_control(&cq_priv->cq_fid.fid, FI_GETWAIT, &mutex_cond);
897 cr_expect_eq(FI_SUCCESS, ret, "fi_control failed.");
898
899 ret = memcmp(&wait_priv->mutex, mutex_cond.mutex,
900 sizeof(*mutex_cond.mutex));
901 cr_expect_eq(0, ret, "mutex compare failed.");
902
903 ret = memcmp(&wait_priv->cond, mutex_cond.cond,
904 sizeof(*mutex_cond.cond));
905 cr_expect_eq(0, ret, "cond compare failed.");
906 }
907
908 Test(cq_wait_ops, none, .init = cq_wait_none_setup)
909 {
910 cr_expect_eq(cq_priv->cq_fid.ops->signal, fi_no_cq_signal,
911 "signal implementation available.");
912 cr_expect_eq(cq_priv->cq_fid.ops->sread, fi_no_cq_sread,
913 "sread implementation available.");
914 cr_expect_eq(cq_priv->cq_fid.ops->sreadfrom, fi_no_cq_sreadfrom,
915 "sreadfrom implementation available.");
916 cr_expect_eq(cq_priv->cq_fid.fid.ops->control, fi_no_control,
917 "control implementation available.");
918 }
919
920 Test(cq_wait_ops, fd, .init = cq_wait_fd_setup, .disabled = true)
921 {
922 cr_expect_neq(cq_priv->cq_fid.ops->signal, fi_no_cq_signal,
923 "signal implementation not available.");
924 cr_expect_neq(cq_priv->cq_fid.fid.ops->control, fi_no_control,
925 "control implementation not available.");
926 }
927
928 Test(cq_wait_set, fd, .init = setup, .disabled = true)
929 {
930 int ret;
931 int fd;
932
933 wait_attr.wait_obj = FI_WAIT_FD;
934
935 ret = fi_wait_open(fab, &wait_attr, &wait_set);
936 cr_expect_eq(FI_SUCCESS, ret, "fi_wait_open failed.");
937
938 wait_priv = container_of(wait_set, struct gnix_fid_wait, wait);
939
940 cq_attr.format = FI_CQ_FORMAT_MSG;
941 cq_attr.size = 8;
942 cq_attr.wait_obj = FI_WAIT_SET;
943 cq_attr.wait_set = wait_set;
944
945 ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
946 cr_expect_eq(FI_SUCCESS, ret, "fi_cq_open failed.");
947
948 cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
949
950 ret = fi_control(&cq_priv->cq_fid.fid, FI_GETWAIT, &fd);
951 cr_expect_eq(FI_SUCCESS, ret, "fi_control failed.");
952
953 cr_expect_eq(wait_priv->fd[WAIT_READ], fd);
954
955 ret = fi_close(&rcq->fid);
956 cr_expect_eq(FI_SUCCESS, ret, "failure in closing cq.");
957
958 ret = fi_close(&wait_set->fid);
959 cr_expect_eq(FI_SUCCESS, ret, "failure in closing waitset.");
960
961 teardown();
962 }
963
964 TestSuite(cq_notify_flags, .init = cq_notify_setup, .fini = cq_notify_teardown);
965
do_cq_notify(uint64_t flags)966 void do_cq_notify(uint64_t flags)
967 {
968 ssize_t ret;
969 struct fi_cq_msg_entry entry;
970
971 ret = _gnix_cq_add_event(cq_priv, ep, NULL, flags, 0, NULL,
972 0, 0, 0);
973 cr_assert(ret == FI_SUCCESS, "failing in _gnix_cq_add_event");
974
975 ret = fi_cq_read(rcq, &entry, 1);
976 cr_assert(ret == 1, "failing in fi_cq_read");
977
978 if (flags & FI_RMA_EVENT) {
979 flags &= (FI_REMOTE_READ | FI_REMOTE_WRITE |
980 FI_RMA | FI_REMOTE_CQ_DATA |
981 FI_MULTI_RECV);
982 } else {
983 flags &= (FI_REMOTE_CQ_DATA | FI_MULTI_RECV);
984 }
985
986 cr_assert_eq(flags, entry.flags, "unexpected cq entry flags");
987 }
988
Test(cq_notify_flags,fi_rma_event)989 Test(cq_notify_flags, fi_rma_event)
990 {
991 do_cq_notify(FI_REMOTE_READ | FI_REMOTE_WRITE |
992 FI_RMA | FI_REMOTE_CQ_DATA |
993 FI_MULTI_RECV | FI_RMA_EVENT);
994 }
995
Test(cq_notify_flags,not_fi_rma_event)996 Test(cq_notify_flags, not_fi_rma_event)
997 {
998 do_cq_notify(~FI_RMA_EVENT);
999 }
1000
1001
1002 struct test_err {
1003 int padding_1;
1004 struct fi_cq_err_entry_1_0 error;
1005 int padding_2;
1006 };
1007
Test(reading_1_4,issue_ofiwg_3227)1008 Test(reading_1_4, issue_ofiwg_3227)
1009 {
1010 struct test_err error_entry;
1011 int ret = 0;
1012 char input_ctx = 'a';
1013 uint64_t flags = 0xb;
1014 size_t len = sizeof(input_ctx);
1015 void *buf = &input_ctx;
1016 uint64_t data = 20;
1017 uint64_t tag = 40;
1018 size_t olen = 20;
1019 int err = 50;
1020 int prov_errno = 80;
1021
1022 /*
1023 * By default CQ start out with no error entries and no entries
1024 * in the error entry free list.
1025 */
1026 cr_assert(!cq_priv->errors->item_list.head);
1027 cr_assert(!cq_priv->errors->free_list.head);
1028
1029 _gnix_cq_add_error(cq_priv, &input_ctx, flags, len, buf, data, tag,
1030 olen, err, prov_errno, 0, 0);
1031
1032 error_entry.padding_1 = 0xcafebabe;
1033 error_entry.padding_2 = 0xcafed00d;
1034
1035 ret = fi_cq_readerr((struct fid_cq *) cq_priv,
1036 (struct fi_cq_err_entry *) &error_entry.error, 0);
1037 cr_assert_eq(ret, 1);
1038
1039 cr_assert_eq(error_entry.padding_1, 0xcafebabe);
1040 cr_assert_eq(error_entry.padding_2, 0xcafed00d);
1041 }
1042