| 140 | } |
| 141 | |
| 142 | size_t |
| 143 | ttyoutq_read(struct ttyoutq *to, void *buf, size_t len) |
| 144 | { |
| 145 | char *cbuf = buf; |
| 146 | |
| 147 | while (len > 0) { |
| 148 | struct ttyoutq_block *tob; |
| 149 | size_t cbegin, cend, clen; |
| 150 | |
| 151 | /* See if there still is data. */ |
| 152 | if (to->to_begin == to->to_end) |
| 153 | break; |
| 154 | tob = to->to_firstblock; |
| 155 | if (tob == NULL) |
| 156 | break; |
| 157 | |
| 158 | /* |
| 159 | * The end address should be the lowest of these three: |
| 160 | * - The write pointer |
| 161 | * - The blocksize - we can't read beyond the block |
| 162 | * - The end address if we could perform the full read |
| 163 | */ |
| 164 | cbegin = to->to_begin; |
| 165 | cend = MIN(MIN(to->to_end, to->to_begin + len), |
| 166 | TTYOUTQ_DATASIZE); |
| 167 | clen = cend - cbegin; |
| 168 | |
| 169 | /* Copy the data out of the buffers. */ |
| 170 | memcpy(cbuf, tob->tob_data + cbegin, clen); |
| 171 | cbuf += clen; |
| 172 | len -= clen; |
| 173 | |
| 174 | if (cend == to->to_end) { |
| 175 | /* Read the complete queue. */ |
| 176 | to->to_begin = 0; |
| 177 | to->to_end = 0; |
| 178 | } else if (cend == TTYOUTQ_DATASIZE) { |
| 179 | /* Read the block until the end. */ |
| 180 | TTYOUTQ_REMOVE_HEAD(to); |
| 181 | to->to_begin = 0; |
| 182 | to->to_end -= TTYOUTQ_DATASIZE; |
| 183 | TTYOUTQ_RECYCLE(to, tob); |
| 184 | } else { |
| 185 | /* Read the block partially. */ |
| 186 | to->to_begin += clen; |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | return (cbuf - (char *)buf); |
| 191 | } |
| 192 | |
| 193 | /* |
| 194 | * An optimized version of ttyoutq_read() which can be used in pseudo |
no test coverage detected