1 /**
2  * Copyright (C) Mellanox Technologies Ltd. 2001-2015.  ALL RIGHTS RESERVED.
3  *
4  * See file LICENSE for terms.
5  */
6 
7 #ifdef HAVE_CONFIG_H
8 #  include "config.h"
9 #endif
10 
11 #include "dt_iov.h"
12 
13 #include <ucs/debug/assert.h>
14 #include <ucs/sys/math.h>
15 
16 #include <string.h>
17 #include <unistd.h>
18 
19 
ucp_dt_iov_gather(void * dest,const ucp_dt_iov_t * iov,size_t length,size_t * iov_offset,size_t * iovcnt_offset)20 void ucp_dt_iov_gather(void *dest, const ucp_dt_iov_t *iov, size_t length,
21                        size_t *iov_offset, size_t *iovcnt_offset)
22 {
23     size_t item_len, item_reminder, item_len_to_copy;
24     size_t length_it = 0;
25 
26     ucs_assert(length > 0);
27     while (length_it < length) {
28         item_len      = iov[*iovcnt_offset].length;
29         item_reminder = item_len - *iov_offset;
30 
31         item_len_to_copy = item_reminder -
32                            ucs_max((ssize_t)((length_it + item_reminder) - length), 0);
33         memcpy(UCS_PTR_BYTE_OFFSET(dest, length_it),
34                UCS_PTR_BYTE_OFFSET(iov[*iovcnt_offset].buffer, *iov_offset),
35                item_len_to_copy);
36         length_it += item_len_to_copy;
37 
38         ucs_assert(length_it <= length);
39         if (length_it < length) {
40             *iov_offset = 0;
41             ++(*iovcnt_offset);
42         } else {
43             *iov_offset += item_len_to_copy;
44         }
45     }
46 }
47 
ucp_dt_iov_scatter(ucp_dt_iov_t * iov,size_t iovcnt,const void * src,size_t length,size_t * iov_offset,size_t * iovcnt_offset)48 size_t ucp_dt_iov_scatter(ucp_dt_iov_t *iov, size_t iovcnt, const void *src,
49                           size_t length, size_t *iov_offset, size_t *iovcnt_offset)
50 {
51     size_t item_len, item_len_to_copy;
52     size_t length_it = 0;
53 
54     while ((length_it < length) && (*iovcnt_offset < iovcnt)) {
55         item_len         = iov[*iovcnt_offset].length;
56         item_len_to_copy = ucs_min(ucs_max((ssize_t)(item_len - *iov_offset), 0),
57                                    length - length_it);
58         ucs_assert(*iov_offset <= item_len);
59 
60         memcpy(UCS_PTR_BYTE_OFFSET(iov[*iovcnt_offset].buffer, *iov_offset),
61                UCS_PTR_BYTE_OFFSET(src, length_it),
62                item_len_to_copy);
63         length_it += item_len_to_copy;
64 
65         ucs_assert(length_it <= length);
66         if (length_it < length) {
67             *iov_offset = 0;
68             ++(*iovcnt_offset);
69         } else {
70             *iov_offset += item_len_to_copy;
71         }
72     }
73     return length_it;
74 }
75 
ucp_dt_iov_seek(ucp_dt_iov_t * iov,size_t iovcnt,ptrdiff_t distance,size_t * iov_offset,size_t * iovcnt_offset)76 void ucp_dt_iov_seek(ucp_dt_iov_t *iov, size_t iovcnt, ptrdiff_t distance,
77                      size_t *iov_offset, size_t *iovcnt_offset)
78 {
79     ssize_t new_iov_offset; /* signed, since it can be negative */
80     size_t length_it;
81 
82     new_iov_offset = ((ssize_t)*iov_offset) + distance;
83 
84     if (new_iov_offset < 0) {
85         /* seek backwards */
86         do {
87             ucs_assert(*iovcnt_offset > 0);
88             --(*iovcnt_offset);
89             new_iov_offset += iov[*iovcnt_offset].length;
90         } while (new_iov_offset < 0);
91     } else {
92         /* seek forward */
93         while (new_iov_offset >= (length_it = iov[*iovcnt_offset].length)) {
94             new_iov_offset -= length_it;
95             ++(*iovcnt_offset);
96             ucs_assert(*iovcnt_offset < iovcnt);
97         }
98     }
99 
100     *iov_offset = new_iov_offset;
101 }
102 
ucp_dt_iov_count_nonempty(const ucp_dt_iov_t * iov,size_t iovcnt)103 size_t ucp_dt_iov_count_nonempty(const ucp_dt_iov_t *iov, size_t iovcnt)
104 {
105     size_t iov_it, count;
106 
107     count = 0;
108     for (iov_it = 0; iov_it < iovcnt; ++iov_it) {
109         count += iov[iov_it].length != 0;
110     }
111     return count;
112 }
113