Search code examples
c++asynchronousoverlapped-io

Reference count for OVERLAPPED structure


I found an article i find quite interesting. There is just one thing i cannot wrap my head around. (http://molecularmusings.wordpress.com/2011/08/31/file-system-part-1-platform-specific-api-design/) The author describes a File class which is able to handle synchronous and asynchronous file operations. For the asynchronous operation he uses a self-contained object which keeps track of the asynchronous operation internally. The class looks like this:

class OsAsyncFileOperation
{
public:
  OsAsyncFileOperation(HANDLE file, size_t position);
  OsAsyncFileOperation(const OsAsyncFileOperation& other);
  OsAsyncFileOperation& operator=(const OsAsyncFileOperation& other);
  ~OsAsyncFileOperation(void);

  /// Returns whether or not the asynchronous operation has finished
  bool HasFinished(void) const;

  /// Waits until the asynchronous operation has finished. Returns the number of transferred bytes.
  size_t WaitUntilFinished(void) const;

  /// Cancels the asynchronous operation
  void Cancel(void);

private:
  HANDLE m_file;
  ReferenceCountedItem<OVERLAPPED>* m_overlapped;
};

And is used like this:

OsAsyncFileOperation ReadAsync(void* buffer, size_t length, size_t position);

Now i am wondering: What is the role of the ReferenceCountedItem<OVERLAPPED>* m_overlapped; variable? I know that this somehow counts the references, but i am not sure how it is used here, especially since the constructor is not getting passed the OVERLAPPED structure. How does this class now about the OVERLAPPED structure used in the ReadAsync or WriteAsync method? I tried to implement the ReferenceCountedItem class, since it is not specified in the article:

#pragma once

template <typename T>
class ReferenceCountedItem {

public:
    ReferenceCountedItem(T* data) :m_data(data), m_refCounter(1)
    {}

    ~ReferenceCountedItem() {}

    int addReference()
    {
        return ++this->m_refCounter;
    }

    int removeReference()
    {
        return --this->m_refCounter;
    }

private:
    T* m_data;
    int m_refCounter;
};

I am mostly unsure of how this all is sticking together. Maybe someone can explain a little bit more about it. If you need more information please let me know.


Solution

  • Somewhere the author is allocating the OVERLAPPED struct on the heap, with new or GlobalAlloc. Then, in the copy constructor and operator=, he is copying the pointer. Since there can be multiple objects using the pointer he is using reference counting to know when it's ok to delete the OVERLAPPED pointer.