Skip to content

Commit 790aaa1

Browse files
committed
Incorporating some feedback on file streams cleanup.
1 parent b029e55 commit 790aaa1

File tree

3 files changed

+53
-32
lines changed

3 files changed

+53
-32
lines changed

Release/include/cpprest/filestream.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,10 +281,17 @@ namespace details {
281281
auto callback = new _filestream_callback_write<size_t>(m_info, result_tce);
282282

283283
// Potentially we should consider deprecating this API, it is TERRIBLY inefficient.
284-
auto sharedCh = std::make_shared<_CharType>(ch);
285-
size_t written = _putn_fsb(m_info, callback, sharedCh.get(), 1, sizeof(_CharType));
286-
284+
std::shared_ptr<_CharType> sharedCh;
285+
try
286+
{
287+
sharedCh = std::make_shared<_CharType>(ch);
288+
} catch (const std::bad_alloc &)
289+
{
290+
delete callback;
291+
throw;
292+
}
287293

294+
size_t written = _putn_fsb(m_info, callback, sharedCh.get(), 1, sizeof(_CharType));
288295
if (written == sizeof(_CharType))
289296
{
290297
delete callback;
@@ -373,8 +380,7 @@ namespace details {
373380
{
374381
if (copy)
375382
{
376-
auto sharedData = std::shared_ptr<_CharType>(new _CharType[count], std::default_delete<_CharType []>());
377-
memcpy(sharedData.get(), ptr, count * sizeof(_CharType));
383+
auto sharedData = std::make_shared<std::vector<_CharType>>(ptr, ptr + count);
378384
return _putn(ptr, count).then([sharedData](size_t size)
379385
{
380386
return size;

Release/include/cpprest/streams.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ namespace Concurrency { namespace streams
303303
{
304304
pplx::task<size_t> result;
305305
if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
306+
// TODO in the future this could be improved to have Value2StringFormatter avoid another unnecessary copy
307+
// by putting the string on the heap before calling the print string overload.
306308
return print(details::Value2StringFormatter<CharType>::format(val));
307309
}
308310

Release/src/streams/fileio_win32.cpp

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ void CALLBACK IoCompletionCallback(
121121
CASABLANCA_UNREFERENCED_PARAMETER(ctxt);
122122
CASABLANCA_UNREFERENCED_PARAMETER(instance);
123123

124-
EXTENDED_OVERLAPPED *pExtOverlapped = (EXTENDED_OVERLAPPED *) pOverlapped;
125-
pExtOverlapped->func(result, (DWORD) numberOfBytesTransferred, (LPOVERLAPPED) pOverlapped);
124+
EXTENDED_OVERLAPPED *pExtOverlapped = static_cast<EXTENDED_OVERLAPPED *>(pOverlapped);
125+
pExtOverlapped->func(result, static_cast<DWORD>(numberOfBytesTransferred), static_cast<LPOVERLAPPED>(pOverlapped));
126126
delete pOverlapped;
127127
}
128128
#endif
@@ -272,7 +272,7 @@ bool __cdecl _close_fsb_nolock(_In_ _file_info **info, _In_ streams::details::_f
272272
_ASSERTE(info != nullptr);
273273
_ASSERTE(*info != nullptr);
274274

275-
_file_info_impl *fInfo = (_file_info_impl *)*info;
275+
_file_info_impl *fInfo = static_cast<_file_info_impl *>(*info);
276276

277277
if ( fInfo->m_handle == INVALID_HANDLE_VALUE ) return false;
278278

@@ -372,7 +372,7 @@ VOID CALLBACK _ReadFileCompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfByte
372372
/// <returns>0 if the write request is still outstanding, -1 if the request failed, otherwise the size of the data written</returns>
373373
size_t _write_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ streams::details::_filestream_callback *callback, const void *ptr, size_t count, size_t position)
374374
{
375-
auto pOverlapped = new EXTENDED_OVERLAPPED(_WriteFileCompletionRoutine<streams::details::_file_info_impl>, callback);
375+
auto pOverlapped = std::unique_ptr<EXTENDED_OVERLAPPED>(new EXTENDED_OVERLAPPED(_WriteFileCompletionRoutine<streams::details::_file_info_impl>, callback));
376376

377377
if (position == static_cast<size_t>(-1))
378378
{
@@ -392,15 +392,19 @@ size_t _write_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ str
392392
#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
393393
StartThreadpoolIo(static_cast<PTP_IO>(fInfo->m_io_context));
394394

395-
BOOL wrResult = WriteFile(fInfo->m_handle, ptr, static_cast<DWORD>(count), nullptr, pOverlapped);
395+
BOOL wrResult = WriteFile(fInfo->m_handle, ptr, static_cast<DWORD>(count), nullptr, pOverlapped.get());
396396
DWORD error = GetLastError();
397397

398398
// WriteFile will return false when a) the operation failed, or b) when the request is still
399399
// pending. The error code will tell us which is which.
400-
if ( wrResult == FALSE && error == ERROR_IO_PENDING )
400+
if (wrResult == FALSE && error == ERROR_IO_PENDING)
401+
{
402+
// Overlapped is deleted in the threadpool callback.
403+
pOverlapped.release();
401404
return 0;
405+
}
402406

403-
CancelThreadpoolIo((PTP_IO)fInfo->m_io_context);
407+
CancelThreadpoolIo(static_cast<PTP_IO>(fInfo->m_io_context));
404408

405409
size_t result = static_cast<size_t>(-1);
406410

@@ -413,14 +417,12 @@ size_t _write_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ str
413417
result = GetOverlappedResult(fInfo->m_handle, pOverlapped, &written, FALSE) ? static_cast<size_t>(written) : static_cast<size_t>(-1);
414418
}
415419

416-
delete pOverlapped;
417-
418420
if (result == static_cast<size_t>(-1))
419421
callback->on_error(std::make_exception_ptr(utility::details::create_system_error(error)));
420422

421423
return result;
422424
#else
423-
BOOL wrResult = WriteFile(fInfo->m_handle, ptr, (DWORD)count, nullptr, pOverlapped);
425+
BOOL wrResult = WriteFile(fInfo->m_handle, ptr, (DWORD)count, nullptr, pOverlapped.get());
424426
DWORD error = GetLastError();
425427

426428
// 1. If WriteFile returned true, it must be because the operation completed immediately.
@@ -431,16 +433,22 @@ size_t _write_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ str
431433
// We do not need to call GetOverlappedResult, the workerthread will call the "on_error()" if the WriteFaile falied.
432434
// "req" is deleted in "_WriteFileCompletionRoutine, "pOverlapped" is deleted in io_scheduler::FileIOCompletionRoutine.
433435
if (wrResult == TRUE)
436+
{
437+
pOverlapped.release();
434438
return 0;
439+
}
435440

436441
// 2. If WriteFile returned false and GetLastError is ERROR_IO_PENDING, return 0,
437442
// The xp threadpool will create a workerthread to run "_WriteFileCompletionRoutine" after the operation completed.
438443
if (wrResult == FALSE && error == ERROR_IO_PENDING)
444+
{
445+
// Overlapped is deleted in the threadpool callback.
446+
pOverlapped.release();
439447
return 0;
448+
}
440449

441-
// 3. If ReadFile returned false and GetLastError is not ERROR_IO_PENDING, we must call "callback->on_error()" and delete.
450+
// 3. If ReadFile returned false and GetLastError is not ERROR_IO_PENDING, we must call "callback->on_error()".
442451
// The threadpools will not start the workerthread.
443-
delete pOverlapped;
444452
callback->on_error(std::make_exception_ptr(utility::details::create_system_error(error)));
445453

446454
return static_cast<size_t>(-1);
@@ -458,7 +466,7 @@ size_t _write_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ str
458466
/// <returns>0 if the read request is still outstanding, -1 if the request failed, otherwise the size of the data read into the buffer</returns>
459467
size_t _read_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ streams::details::_filestream_callback *callback, _Out_writes_ (count) void *ptr, _In_ size_t count, size_t offset)
460468
{
461-
auto pOverlapped = new EXTENDED_OVERLAPPED(_ReadFileCompletionRoutine<streams::details::_file_info_impl>, callback);
469+
auto pOverlapped = std::unique_ptr<EXTENDED_OVERLAPPED>(new EXTENDED_OVERLAPPED(_ReadFileCompletionRoutine<streams::details::_file_info_impl>, callback));
462470
pOverlapped->Offset = static_cast<DWORD>(offset);
463471
#ifdef _WIN64
464472
pOverlapped->OffsetHigh = static_cast<DWORD>(offset >> 32);
@@ -469,24 +477,26 @@ size_t _read_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ stre
469477
#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
470478
StartThreadpoolIo((PTP_IO)fInfo->m_io_context);
471479

472-
BOOL wrResult = ReadFile(fInfo->m_handle, ptr, static_cast<DWORD>(count), nullptr, pOverlapped);
480+
BOOL wrResult = ReadFile(fInfo->m_handle, ptr, static_cast<DWORD>(count), nullptr, pOverlapped.get());
473481
DWORD error = GetLastError();
474482

475483
// ReadFile will return false when a) the operation failed, or b) when the request is still
476484
// pending. The error code will tell us which is which.
477-
478-
if ( wrResult == FALSE && error == ERROR_IO_PENDING )
485+
if (wrResult == FALSE && error == ERROR_IO_PENDING)
486+
{
487+
// Overlapped is deleted in the threadpool callback.
488+
pOverlapped.release();
479489
return 0;
490+
}
480491

481492
// We find ourselves here because there was a synchronous completion, either with an error or
482493
// success. Either way, we don't need the thread pool I/O request here, or the request and
483494
// overlapped structures.
484-
485495
CancelThreadpoolIo(static_cast<PTP_IO>(fInfo->m_io_context));
486496

487497
size_t result = static_cast<size_t>(-1);
488498

489-
if ( wrResult == TRUE )
499+
if (wrResult == TRUE)
490500
{
491501
// If ReadFile returned true, it must be because the operation completed immediately.
492502
// However, we didn't pass in an address for the number of bytes written, so
@@ -495,20 +505,18 @@ size_t _read_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ stre
495505
result = GetOverlappedResult(fInfo->m_handle, pOverlapped, &read, FALSE) ? static_cast<size_t>(read) : static_cast<size_t>(-1);
496506
}
497507

498-
delete pOverlapped;
499-
500-
if ( wrResult == FALSE && error == ERROR_HANDLE_EOF )
508+
if (wrResult == FALSE && error == ERROR_HANDLE_EOF)
501509
{
502510
callback->on_completed(0);
503511
return 0;
504512
}
505513

506-
if ( result == static_cast<size_t>(-1) )
514+
if (result == static_cast<size_t>(-1))
507515
callback->on_error(std::make_exception_ptr(utility::details::create_system_error(error)));
508516

509517
return result;
510518
#else
511-
BOOL wrResult = ReadFile(fInfo->m_handle, ptr, static_cast<DWORD>(count), nullptr, pOverlapped);
519+
BOOL wrResult = ReadFile(fInfo->m_handle, ptr, static_cast<DWORD>(count), nullptr, pOverlapped.get());
512520
DWORD error = GetLastError();
513521

514522
// 1. If ReadFile returned true, it must be because the operation completed immediately.
@@ -519,25 +527,30 @@ size_t _read_file_async(_In_ streams::details::_file_info_impl *fInfo, _In_ stre
519527
// We do not need to call GetOverlappedResult, the workerthread will call the "on_error()" if the ReadFile falied.
520528
// "req" is deleted in "_ReadFileCompletionRoutine, "pOverlapped" is deleted in io_scheduler::FileIOCompletionRoutine.
521529
if (wrResult == TRUE)
530+
{
531+
pOverlapped.release();
522532
return 0;
533+
}
523534

524535
// 2. If ReadFile returned false and GetLastError is ERROR_IO_PENDING, return 0.
525536
// The xp threadpool will create a workerthread to run "_WriteFileCompletionRoutine" after the operation completed.
526537
if (wrResult == FALSE && error == ERROR_IO_PENDING)
538+
{
539+
// Overlapped is deleted in the threadpool callback.
540+
pOverlapped.release();
527541
return 0;
542+
}
528543

529-
// 3. If ReadFile returned false and GetLastError is ERROR_HANDLE_EOF, we must call "callback->on_completed(0)" and delete.
544+
// 3. If ReadFile returned false and GetLastError is ERROR_HANDLE_EOF, we must call "callback->on_completed(0)".
530545
// The threadpool will not start the workerthread.
531546
if (wrResult == FALSE && error == ERROR_HANDLE_EOF)
532547
{
533-
delete pOverlapped;
534548
callback->on_completed(0);
535549
return 0;
536550
}
537551

538-
// 4. If ReadFile returned false and GetLastError is not a valid error code, we must call "callback->on_error()" and delete.
552+
// 4. If ReadFile returned false and GetLastError is not a valid error code, we must call "callback->on_error()".
539553
// The threadpool will not start the workerthread.
540-
delete pOverlapped;
541554
callback->on_error(std::make_exception_ptr(utility::details::create_system_error(error)));
542555

543556
return static_cast<size_t>(-1);

0 commit comments

Comments
 (0)