Send a file using a zero-copy function.
(self, zerocopy_func, giveup_exc_type, file,
offset=0, count=None)
| 350 | return text |
| 351 | |
| 352 | def _sendfile_zerocopy(self, zerocopy_func, giveup_exc_type, file, |
| 353 | offset=0, count=None): |
| 354 | """ |
| 355 | Send a file using a zero-copy function. |
| 356 | """ |
| 357 | import selectors |
| 358 | |
| 359 | self._check_sendfile_params(file, offset, count) |
| 360 | sockno = self.fileno() |
| 361 | try: |
| 362 | fileno = file.fileno() |
| 363 | except (AttributeError, io.UnsupportedOperation) as err: |
| 364 | raise giveup_exc_type(err) # not a regular file |
| 365 | try: |
| 366 | fsize = os.fstat(fileno).st_size |
| 367 | except OSError as err: |
| 368 | raise giveup_exc_type(err) # not a regular file |
| 369 | if not fsize: |
| 370 | return 0 # empty file |
| 371 | # Truncate to 1GiB to avoid OverflowError, see bpo-38319. |
| 372 | blocksize = min(count or fsize, 2 ** 30) |
| 373 | timeout = self.gettimeout() |
| 374 | if timeout == 0: |
| 375 | raise ValueError("non-blocking sockets are not supported") |
| 376 | # poll/select have the advantage of not requiring any |
| 377 | # extra file descriptor, contrarily to epoll/kqueue |
| 378 | # (also, they require a single syscall). |
| 379 | if hasattr(selectors, 'PollSelector'): |
| 380 | selector = selectors.PollSelector() |
| 381 | else: |
| 382 | selector = selectors.SelectSelector() |
| 383 | selector.register(sockno, selectors.EVENT_WRITE) |
| 384 | |
| 385 | total_sent = 0 |
| 386 | # localize variable access to minimize overhead |
| 387 | selector_select = selector.select |
| 388 | try: |
| 389 | while True: |
| 390 | if timeout and not selector_select(timeout): |
| 391 | raise TimeoutError('timed out') |
| 392 | if count: |
| 393 | blocksize = min(count - total_sent, blocksize) |
| 394 | if blocksize <= 0: |
| 395 | break |
| 396 | try: |
| 397 | sent = zerocopy_func(fileno, offset, blocksize) |
| 398 | except BlockingIOError: |
| 399 | if not timeout: |
| 400 | # Block until the socket is ready to send some |
| 401 | # data; avoids hogging CPU resources. |
| 402 | selector_select() |
| 403 | continue |
| 404 | except OSError as err: |
| 405 | if total_sent == 0: |
| 406 | # We can get here for different reasons, the main |
| 407 | # one being 'file' is not a regular mmap(2)-like |
| 408 | # file, in which case we'll fall back on using |
| 409 | # plain send(). |
no test coverage detected