diff --git psutil/__init__.py psutil/__init__.py
index ca2d9273..26a567ec 100644
--- psutil/__init__.py
+++ psutil/__init__.py
@@ -14,6 +14,7 @@ sensors) in Python. Supported platforms:
  - FreeBSD
  - OpenBSD
  - NetBSD
+ - DragonFly BSD
  - Sun Solaris
  - AIX
 
@@ -55,6 +56,7 @@ from ._common import CONN_SYN_RECV
 from ._common import CONN_SYN_SENT
 from ._common import CONN_TIME_WAIT
 from ._common import FREEBSD  # NOQA
+from ._common import DRAGONFLY  # NOQA
 from ._common import LINUX
 from ._common import MACOS
 from ._common import NETBSD  # NOQA
@@ -170,7 +172,7 @@ __all__ = [
     "POWER_TIME_UNKNOWN", "POWER_TIME_UNLIMITED",
 
     "BSD", "FREEBSD", "LINUX", "NETBSD", "OPENBSD", "MACOS", "OSX", "POSIX",
-    "SUNOS", "WINDOWS", "AIX",
+    "DRAGONFLY", "SUNOS", "WINDOWS", "AIX",
 
     # "RLIM_INFINITY", "RLIMIT_AS", "RLIMIT_CORE", "RLIMIT_CPU", "RLIMIT_DATA",
     # "RLIMIT_FSIZE", "RLIMIT_LOCKS", "RLIMIT_MEMLOCK", "RLIMIT_NOFILE",
diff --git psutil/_common.py psutil/_common.py
index 3414e8ca..d9894b5c 100644
--- psutil/_common.py
+++ psutil/_common.py
@@ -49,7 +49,7 @@ _DEFAULT = object()
 __all__ = [
     # OS constants
     'FREEBSD', 'BSD', 'LINUX', 'NETBSD', 'OPENBSD', 'MACOS', 'OSX', 'POSIX',
-    'SUNOS', 'WINDOWS',
+    'DRAGONFLY', 'SUNOS', 'WINDOWS',
     # connection constants
     'CONN_CLOSE', 'CONN_CLOSE_WAIT', 'CONN_CLOSING', 'CONN_ESTABLISHED',
     'CONN_FIN_WAIT1', 'CONN_FIN_WAIT2', 'CONN_LAST_ACK', 'CONN_LISTEN',
@@ -91,7 +91,8 @@ OSX = MACOS  # deprecated alias
 FREEBSD = sys.platform.startswith(("freebsd", "midnightbsd"))
 OPENBSD = sys.platform.startswith("openbsd")
 NETBSD = sys.platform.startswith("netbsd")
-BSD = FREEBSD or OPENBSD or NETBSD
+DRAGONFLY = sys.platform.startswith("dragonfly")
+BSD = FREEBSD or OPENBSD or NETBSD or DRAGONFLY
 SUNOS = sys.platform.startswith(("sunos", "solaris"))
 AIX = sys.platform.startswith("aix")
 
@@ -116,6 +117,7 @@ STATUS_LOCKED = "locked"  # FreeBSD
 STATUS_WAITING = "waiting"  # FreeBSD
 STATUS_SUSPENDED = "suspended"  # NetBSD
 STATUS_PARKED = "parked"  # Linux
+STATUS_CORE = "core" # DragonFly
 
 # Process.connections() and psutil.net_connections()
 CONN_ESTABLISHED = "ESTABLISHED"
diff --git psutil/_psbsd.py psutil/_psbsd.py
index a25c96cd..c886d56c 100644
--- psutil/_psbsd.py
+++ psutil/_psbsd.py
@@ -19,6 +19,7 @@ from . import _psutil_posix as cext_posix
 from ._common import FREEBSD
 from ._common import NETBSD
 from ._common import OPENBSD
+from ._common import DRAGONFLY
 from ._common import AccessDenied
 from ._common import NoSuchProcess
 from ._common import ZombieProcess
@@ -51,6 +52,14 @@ if FREEBSD:
         cext.SWAIT: _common.STATUS_WAITING,
         cext.SLOCK: _common.STATUS_LOCKED,
     }
+elif DRAGONFLY:
+    PROC_STATUSES = {
+        cext.SIDL: _common.STATUS_IDLE,
+        cext.SACTIVE: _common.STATUS_RUNNING,
+        cext.SSTOP: _common.STATUS_STOPPED,
+        cext.SZOMB: _common.STATUS_ZOMBIE,
+        cext.SCORE: _common.STATUS_CORE,
+    }
 elif OPENBSD:
     PROC_STATUSES = {
         cext.SIDL: _common.STATUS_IDLE,
@@ -166,6 +175,10 @@ if FREEBSD:
                                      'read_bytes', 'write_bytes',
                                      'read_time', 'write_time',
                                      'busy_time'])
+elif DRAGONFLY:
+    sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
+                                     'read_bytes', 'write_bytes',
+                                     'busy_time'])
 else:
     sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
                                      'read_bytes', 'write_bytes'])
@@ -254,6 +267,9 @@ if OPENBSD or NETBSD:
     def cpu_count_cores():
         # OpenBSD and NetBSD do not implement this.
         return 1 if cpu_count_logical() == 1 else None
+elif DRAGONFLY:
+    def cpu_count_cores():
+        return cext.cpu_count_cores()
 else:
     def cpu_count_cores():
         """Return the number of CPU cores in the system."""
@@ -284,7 +300,7 @@ else:
 
 def cpu_stats():
     """Return various CPU stats as a named tuple."""
-    if FREEBSD:
+    if FREEBSD or DRAGONFLY:
         # Note: the C ext is returning some metrics we are not exposing:
         # traps.
         ctxsw, intrs, soft_intrs, syscalls, traps = cext.cpu_stats()
@@ -774,7 +790,7 @@ class Process(object):
             raise ValueError("invalid %r kind argument; choose between %s"
                              % (kind, ', '.join([repr(x) for x in conn_tmap])))
 
-        if NETBSD:
+        if NETBSD or DRAGONFLY:
             families, types = conn_tmap[kind]
             ret = []
             rawlist = cext.net_connections(self.pid)
diff --git psutil/_psutil_bsd.c psutil/_psutil_bsd.c
index 1ffa7b00..8e7c123b 100644
--- psutil/_psutil_bsd.c
+++ psutil/_psutil_bsd.c
@@ -101,6 +101,17 @@
     #ifndef DTYPE_VNODE
         #define DTYPE_VNODE 1
     #endif
+#elif PSUTIL_DRAGONFLY
+    #include "arch/dragonfly/cpu.h"
+    #include "arch/dragonfly/mem.h"
+    #include "arch/dragonfly/disk.h"
+    #include "arch/dragonfly/sensors.h"
+    #include "arch/dragonfly/proc.h"
+    #include "arch/dragonfly/sys_socks.h"
+    #include "arch/dragonfly/proc_socks.h"
+    #include <sys/resource.h>
+
+    #include <utmpx.h>
 #endif
 
 
@@ -135,11 +146,17 @@ psutil_pids(PyObject *self, PyObject *args) {
         for (idx = 0; idx < num_processes; idx++) {
 #ifdef PSUTIL_FREEBSD
             py_pid = PyLong_FromPid(proclist->ki_pid);
+#elif defined(PSUTIL_DRAGONFLY)
+	    py_pid = PyLong_FromPid(proclist->kp_pid);
 #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
             py_pid = PyLong_FromPid(proclist->p_pid);
 #endif
             if (!py_pid)
                 goto error;
+#ifdef PSUTIL_DRAGONFLY
+	    /* TODO(tuxillo): Kernel threads not included for now */
+	    if (proclist->kp_pid != -1)
+#endif
             if (PyList_Append(py_retlist, py_pid))
                 goto error;
             Py_CLEAR(py_pid);
@@ -204,6 +221,8 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
     // Process
 #ifdef PSUTIL_FREEBSD
     sprintf(str, "%s", kp.ki_comm);
+#elif defined(PSUTIL_DRAGONFLY)
+    sprintf(str, "%s", kp.kp_comm);
 #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
     sprintf(str, "%s", kp.p_comm);
 #endif
@@ -223,6 +242,12 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
     memtext = (long)kp.ki_tsize * pagesize;
     memdata = (long)kp.ki_dsize * pagesize;
     memstack = (long)kp.ki_ssize * pagesize;
+#elif PSUTIL_DRAGONFLY
+    rss = (long)kp.kp_vm_rssize * pagesize;
+    vms = (long)kp.kp_vm_map_size;
+    memtext = (long)kp.kp_vm_tsize * pagesize;
+    memdata = (long)kp.kp_vm_dsize * pagesize;
+    memstack = (long)kp.kp_vm_ssize * pagesize;
 #else
     rss = (long)kp.p_vm_rssize * pagesize;
     #ifdef PSUTIL_OPENBSD
@@ -250,6 +275,8 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
         oncpu = kp.ki_oncpu;
     else
         oncpu = kp.ki_lastcpu;
+#elif defined(PSUTIL_DRAGONFLY)
+    oncpu = kp.kp_lwp.kl_cpuid;
 #else
     // On Net/OpenBSD we have kp.p_cpuid but it appears it's always
     // set to KI_NOCPU. Even if it's not, ki_lastcpu does not exist
@@ -260,6 +287,8 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
 
 #ifdef PSUTIL_FREEBSD
     py_ppid = PyLong_FromPid(kp.ki_ppid);
+#elif defined(PSUTIL_DRAGONFLY)
+    py_ppid = PyLong_FromPid(kp.kp_ppid);
 #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
     py_ppid = PyLong_FromPid(kp.p_ppid);
 #else
@@ -308,6 +337,39 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
         memstack,                         // (long) mem stack
         // others
         oncpu,                            // (int) the CPU we are on
+#elif defined(PSUTIL_DRAGONFLY)
+        py_ppid,                         // (pid_t) ppid
+        (int)kp.kp_stat,                 // (int) status
+        // UIDs
+        (long)kp.kp_ruid,                // (long) real uid
+        (long)kp.kp_uid,                 // (long) effective uid
+        (long)kp.kp_svuid,               // (long) saved uid
+        // GIDs
+        (long)kp.kp_rgid,                // (long) real gid
+        (long)kp.kp_groups[0],           // (long) effective gid
+        (long)kp.kp_svuid,               // (long) saved gid
+        //
+        kp.kp_tdev,                      // (int or long long) tty nr
+        PSUTIL_TV2DOUBLE(kp.kp_start),   // (double) create time
+        // ctx switches
+        kp.kp_ru.ru_nvcsw,           // (long) ctx switches (voluntary)
+        kp.kp_ru.ru_nivcsw,          // (long) ctx switches (unvoluntary)
+        // IO count
+        kp.kp_ru.ru_inblock,         // (long) read io count
+        kp.kp_ru.ru_oublock,         // (long) write io count
+        // CPU times: convert from micro seconds to seconds.
+        PSUTIL_TV2DOUBLE(kp.kp_ru.ru_utime),     // (double) user time
+        PSUTIL_TV2DOUBLE(kp.kp_ru.ru_stime),     // (double) sys time
+        PSUTIL_TV2DOUBLE(kp.kp_cru.ru_utime),  // (double) children utime
+        PSUTIL_TV2DOUBLE(kp.kp_cru.ru_stime),  // (double) children stime
+        // memory
+        rss,                              // (long) rss
+        vms,                              // (long) vms
+        memtext,                          // (long) mem text
+        memdata,                          // (long) mem data
+        memstack,                         // (long) mem stack
+        // others
+        oncpu,                            // (int) the CPU we are on
 #elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
         py_ppid,                         // (pid_t) ppid
         (int)kp.p_stat,                  // (int) status
@@ -412,8 +474,10 @@ psutil_proc_environ(PyObject *self, PyObject *args) {
     if (!PyArg_ParseTuple(args, "l", &pid))
         return NULL;
 
-#if defined(PSUTIL_FREEBSD)
+#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_DRAGONFLY)
     kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf);
+#elif defined(PSUTIL_DRAGONFLY)
+    kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
 #else
     kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
 #endif
@@ -458,6 +522,8 @@ psutil_proc_environ(PyObject *self, PyObject *args) {
 #endif
 #elif defined(PSUTIL_NETBSD)
     if ((p)->p_stat == SZOMB) {
+#elif defined(PSUTIL_DRAGONFLY)
+    if ((p)->kp_flags & P_SYSTEM) {
 #elif defined(PSUTIL_OPENBSD)
     if ((p)->p_flag & P_SYSTEM) {
 #endif
@@ -1072,14 +1138,16 @@ static PyMethodDef mod_methods[] = {
     {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS},
     {"proc_open_files", psutil_proc_open_files, METH_VARARGS},
 #endif
-#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD)
+#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD) || defined(PSUTIL_DRAGONFLY)
     {"proc_num_threads", psutil_proc_num_threads, METH_VARARGS},
 #endif
-#if defined(PSUTIL_FREEBSD)
+#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_DRAGONFLY)
     {"cpu_topology", psutil_cpu_topology, METH_VARARGS},
     {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS},
     {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS},
     {"proc_exe", psutil_proc_exe, METH_VARARGS},
+#endif
+#if defined(PSUTIL_FREEBSD)
     {"proc_getrlimit", psutil_proc_getrlimit, METH_VARARGS},
     {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS},
     {"proc_setrlimit", psutil_proc_setrlimit, METH_VARARGS},
@@ -1102,12 +1170,15 @@ static PyMethodDef mod_methods[] = {
 #if defined(PSUTIL_FREEBSD) || defined(PSUTIL_OPENBSD)
      {"cpu_freq", psutil_cpu_freq, METH_VARARGS},
 #endif
-#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD)
+#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD) || defined(PSUTIL_DRAGONFLY)
     {"net_connections", psutil_net_connections, METH_VARARGS},
 #endif
 #if defined(PSUTIL_FREEBSD)
     {"sensors_battery", psutil_sensors_battery, METH_VARARGS},
     {"sensors_cpu_temperature", psutil_sensors_cpu_temperature, METH_VARARGS},
+#endif
+#ifdef PSUTIL_DRAGONFLY
+    {"cpu_count_cores", psutil_cpu_count_cores, METH_VARARGS},
 #endif
     // --- others
     {"set_debug", psutil_set_debug, METH_VARARGS},
@@ -1157,6 +1228,12 @@ static PyMethodDef mod_methods[] = {
     if (PyModule_AddIntConstant(mod, "SZOMB", SZOMB)) INITERR;
     if (PyModule_AddIntConstant(mod, "SWAIT", SWAIT)) INITERR;
     if (PyModule_AddIntConstant(mod, "SLOCK", SLOCK)) INITERR;
+#elif defined(PSUTIL_DRAGONFLY)
+    if (PyModule_AddIntConstant(mod, "SIDL", SIDL)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SACTIVE", SACTIVE)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SSTOP", SSTOP)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SZOMB", SZOMB)) INITERR;
+    if (PyModule_AddIntConstant(mod, "SCORE", SCORE)) INITERR;
 #elif  PSUTIL_OPENBSD
     if (PyModule_AddIntConstant(mod, "SIDL", SIDL)) INITERR;
     if (PyModule_AddIntConstant(mod, "SRUN", SRUN)) INITERR;
diff --git psutil/_psutil_common.c psutil/_psutil_common.c
index 096e2f37..eb588cd7 100644
--- psutil/_psutil_common.c
+++ psutil/_psutil_common.c
@@ -155,7 +155,8 @@ psutil_set_debug(PyObject *self, PyObject *args) {
 // Utility functions (BSD)
 // ============================================================================
 
-#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
+#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD) || \
+    defined(PSUTIL_DRAGONFLY)
 void
 convert_kvm_err(const char *syscall, char *errbuf) {
     char fullmsg[8192];
diff --git psutil/arch/dragonfly/cpu.c psutil/arch/dragonfly/cpu.c
new file mode 100644
index 00000000..581182a6
--- /dev/null
+++ psutil/arch/dragonfly/cpu.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+System-wide CPU related functions.
+Original code was refactored and moved from psutil/arch/freebsd/specific.c
+in 2020 (and was moved in there previously already) from cset.
+a4c0a0eb0d2a872ab7a45e47fcf37ef1fde5b012
+For reference, here's the git history with original(ish) implementations:
+- CPU stats: fb0154ef164d0e5942ac85102ab660b8d2938fbb
+- CPU freq: 459556dd1e2979cdee22177339ced0761caf4c83
+- CPU cores: e0d6d7865df84dc9a1d123ae452fd311f79b1dde
+*/
+
+
+#include <Python.h>
+#include <sys/sysctl.h>
+#include <devstat.h>
+#include <sys/resource.h>
+
+#include "../../_psutil_common.h"
+#include "../../_psutil_posix.h"
+
+
+/*
+ * Return the number of cores in the system.
+ */
+PyObject *
+psutil_cpu_count_cores(PyObject *self, PyObject *args) {
+    int mib[2];
+    int phys_cpus;
+    int cpu_cores;
+    size_t len;
+
+    // physical cpus
+    if (sysctlbyname("hw.cpu_topology_phys_ids", &phys_cpus, &len, NULL, 0) == -1) {
+        PyErr_SetFromOSErrnoWithSyscall("sysctlbyname('hw.cpu_topology_phys_ids')");
+        Py_RETURN_NONE;  // mimic os.cpu_count()
+    }
+
+    // cores per package
+    if (sysctlbyname("hw.cpu_topology_core_ids", &cpu_cores, &len, NULL, 0) == -1) {
+        PyErr_SetFromOSErrnoWithSyscall("sysctlbyname('hw.cpu_topology_core_ids')");
+        Py_RETURN_NONE;  // mimic os.cpu_count()
+    }
+
+    return Py_BuildValue("i", phys_cpus * cpu_cores);
+}
+
+PyObject *
+psutil_per_cpu_times(PyObject *self, PyObject *args) {
+    static int maxcpus;
+    int mib[2];
+    int ncpu;
+    size_t len;
+    size_t size;
+    int i;
+    PyObject *py_retlist = PyList_New(0);
+    PyObject *py_cputime = NULL;
+
+    if (py_retlist == NULL)
+        return NULL;
+
+    // retrieve maxcpus value
+    size = sizeof(maxcpus);
+    if (sysctlbyname("hw.ncpu", &maxcpus, &size, NULL, 0) < 0) {
+        Py_DECREF(py_retlist);
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('hw.ncpu')");
+    }
+    long cpu_time[maxcpus][CPUSTATES];
+
+    // retrieve the number of cpus
+    mib[0] = CTL_HW;
+    mib[1] = HW_NCPU;
+    len = sizeof(ncpu);
+    if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
+        PyErr_SetFromOSErrnoWithSyscall("sysctl(HW_NCPU)");
+        goto error;
+    }
+
+    // per-cpu info
+    size = sizeof(cpu_time);
+    if (sysctlbyname("kern.cp_times", &cpu_time, &size, NULL, 0) == -1) {
+        PyErr_SetFromOSErrnoWithSyscall("sysctlbyname('kern.cp_times')");
+        goto error;
+    }
+
+    for (i = 0; i < ncpu; i++) {
+        py_cputime = Py_BuildValue(
+            "(ddddd)",
+            (double)cpu_time[i][CP_USER] / CLOCKS_PER_SEC,
+            (double)cpu_time[i][CP_NICE] / CLOCKS_PER_SEC,
+            (double)cpu_time[i][CP_SYS] / CLOCKS_PER_SEC,
+            (double)cpu_time[i][CP_IDLE] / CLOCKS_PER_SEC,
+            (double)cpu_time[i][CP_INTR] / CLOCKS_PER_SEC);
+        if (!py_cputime)
+            goto error;
+        if (PyList_Append(py_retlist, py_cputime))
+            goto error;
+        Py_DECREF(py_cputime);
+    }
+
+    return py_retlist;
+
+error:
+    Py_XDECREF(py_cputime);
+    Py_DECREF(py_retlist);
+    return NULL;
+}
+
+
+PyObject *
+psutil_cpu_topology(PyObject *self, PyObject *args) {
+    void *topology = NULL;
+    size_t size = 0;
+    PyObject *py_str;
+
+    if (sysctlbyname("hw.cpu_topology.tree", NULL, &size, NULL, 0))
+        goto error;
+
+    topology = malloc(size);
+    if (!topology) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+
+    if (sysctlbyname("hw.cpu_topology.tree", topology, &size, NULL, 0))
+        goto error;
+
+    py_str = Py_BuildValue("s", topology);
+    free(topology);
+    return py_str;
+
+error:
+    if (topology != NULL)
+        free(topology);
+    Py_RETURN_NONE;
+}
+
+
+PyObject *
+psutil_cpu_stats(PyObject *self, PyObject *args) {
+    unsigned int v_soft;
+    unsigned int v_intr;
+    unsigned int v_syscall;
+    unsigned int v_trap;
+    unsigned int v_swtch;
+    size_t size = sizeof(v_soft);
+
+    if (sysctlbyname("vm.stats.sys.v_soft", &v_soft, &size, NULL, 0)) {
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('vm.stats.sys.v_soft')");
+    }
+    if (sysctlbyname("vm.stats.sys.v_intr", &v_intr, &size, NULL, 0)) {
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('vm.stats.sys.v_intr')");
+    }
+    if (sysctlbyname("vm.stats.sys.v_syscall", &v_syscall, &size, NULL, 0)) {
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('vm.stats.sys.v_syscall')");
+    }
+    if (sysctlbyname("vm.stats.sys.v_trap", &v_trap, &size, NULL, 0)) {
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('vm.stats.sys.v_trap')");
+    }
+    if (sysctlbyname("vm.stats.sys.v_swtch", &v_swtch, &size, NULL, 0)) {
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('vm.stats.sys.v_swtch')");
+    }
+
+    return Py_BuildValue(
+        "IIIII",
+        v_swtch,  // ctx switches
+        v_intr,  // interrupts
+        v_soft,  // software interrupts
+        v_syscall,  // syscalls
+        v_trap  // traps
+    );
+}
diff --git psutil/arch/dragonfly/cpu.h psutil/arch/dragonfly/cpu.h
new file mode 100644
index 00000000..a0de54f0
--- /dev/null
+++ psutil/arch/dragonfly/cpu.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <Python.h>
+
+PyObject *psutil_cpu_freq(PyObject* self, PyObject* args);
+PyObject *psutil_cpu_stats(PyObject* self, PyObject* args);
+PyObject *psutil_cpu_topology(PyObject* self, PyObject* args);
+PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args);
+PyObject *psutil_cpu_count_cores(PyObject *self, PyObject *args);
diff --git psutil/arch/dragonfly/disk.c psutil/arch/dragonfly/disk.c
new file mode 100644
index 00000000..2704fd73
--- /dev/null
+++ psutil/arch/dragonfly/disk.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <Python.h>
+#include <sys/sysctl.h>
+#include <devstat.h>
+
+#include "../../_psutil_common.h"
+#include "../../_psutil_posix.h"
+
+
+// convert a bintime struct to milliseconds
+#define PSUTIL_BT2MSEC(bt) (bt.sec * 1000 + (((uint64_t) 1000000000 * (uint32_t) \
+        (bt.frac >> 32) ) >> 32 ) / 1000000)
+
+#define PSUTIL_TV2MSEC(tv) (tv.tv_sec * 1000 + (1000000L * tv.tv_usec))
+
+
+PyObject *
+psutil_disk_io_counters(PyObject *self, PyObject *args) {
+    int i;
+    struct statinfo stats;
+
+    PyObject *py_retdict = PyDict_New();
+    PyObject *py_disk_info = NULL;
+
+    if (py_retdict == NULL)
+        return NULL;
+    if (checkversion() < 0) {
+        PyErr_Format(PyExc_RuntimeError,
+                     "devstat_checkversion() syscall failed");
+        goto error;
+    }
+
+    stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
+    if (stats.dinfo == NULL) {
+        PyErr_NoMemory();
+        goto error;
+    }
+    bzero(stats.dinfo, sizeof(struct devinfo));
+
+    if (getdevs(&stats) == -1) {
+        PyErr_Format(PyExc_RuntimeError, "devstat_getdevs() syscall failed");
+        goto error;
+    }
+
+    for (i = 0; i < stats.dinfo->numdevs; i++) {
+        py_disk_info = NULL;
+        struct devstat current;
+        char disk_name[128];
+        current = stats.dinfo->devices[i];
+        snprintf(disk_name, sizeof(disk_name), "%s%d",
+                 current.device_name,
+                 current.unit_number);
+
+        py_disk_info = Py_BuildValue(
+            "(KKKKL)",
+            current.num_reads,   // no reads
+            current.num_writes,  // no writes
+            current.bytes_read,        // bytes read
+            current.bytes_written,       // bytes written
+            (long long) PSUTIL_TV2MSEC(current.busy_time)  // busy time
+        );      // finished transactions
+        if (!py_disk_info)
+            goto error;
+        if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info))
+            goto error;
+        Py_DECREF(py_disk_info);
+    }
+
+    if (stats.dinfo->mem_ptr)
+        free(stats.dinfo->mem_ptr);
+    free(stats.dinfo);
+    return py_retdict;
+
+error:
+    Py_XDECREF(py_disk_info);
+    Py_DECREF(py_retdict);
+    if (stats.dinfo != NULL)
+        free(stats.dinfo);
+    return NULL;
+}
+
diff --git psutil/arch/dragonfly/disk.h psutil/arch/dragonfly/disk.h
new file mode 100644
index 00000000..9e29f664
--- /dev/null
+++ psutil/arch/dragonfly/disk.h
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <Python.h>
+
+PyObject *psutil_disk_io_counters(PyObject* self, PyObject* args);
diff --git psutil/arch/dragonfly/mem.c psutil/arch/dragonfly/mem.c
new file mode 100644
index 00000000..bda5159d
--- /dev/null
+++ psutil/arch/dragonfly/mem.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include <Python.h>
+#include <sys/sysctl.h>
+#include <sys/vmmeter.h>
+#include <vm/vm_param.h>
+#include <devstat.h>
+#include <paths.h>
+#include <fcntl.h>
+
+#include <kvm.h>
+
+#include "../../_psutil_common.h"
+#include "../../_psutil_posix.h"
+
+
+#ifndef _PATH_DEVNULL
+    #define _PATH_DEVNULL "/dev/null"
+#endif
+
+
+PyObject *
+psutil_virtual_mem(PyObject *self, PyObject *args) {
+    unsigned long  total;
+    unsigned int   active, inactive, wired, cached, free;
+    size_t         size = sizeof(total);
+    struct vmtotal vm;
+    int            mib[] = {CTL_VM, VM_METER};
+    long           pagesize = psutil_getpagesize();
+    long buffers;
+    size_t buffers_size = sizeof(buffers);
+
+    if (sysctlbyname("hw.physmem", &total, &size, NULL, 0)) {
+        return PyErr_SetFromOSErrnoWithSyscall("sysctlbyname('hw.physmem')");
+    }
+    if (sysctlbyname("vm.stats.vm.v_active_count", &active, &size, NULL, 0)) {
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('vm.stats.vm.v_active_count')");
+    }
+    if (sysctlbyname("vm.stats.vm.v_inactive_count", &inactive, &size, NULL, 0))
+    {
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('vm.stats.vm.v_inactive_count')");
+    }
+    if (sysctlbyname("vm.stats.vm.v_wire_count", &wired, &size, NULL, 0)) {
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('vm.stats.vm.v_wire_count')");
+    }
+    // https://github.com/giampaolo/psutil/issues/997
+    if (sysctlbyname("vm.stats.vm.v_cache_count", &cached, &size, NULL, 0)) {
+        cached = 0;
+    }
+    if (sysctlbyname("vm.stats.vm.v_free_count", &free, &size, NULL, 0)) {
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('vm.stats.vm.v_free_count')");
+    }
+    if (sysctlbyname("vfs.bufspace", &buffers, &buffers_size, NULL, 0)) {
+        return PyErr_SetFromOSErrnoWithSyscall("sysctlbyname('vfs.bufspace')");
+    }
+
+    size = sizeof(vm);
+    if (sysctlbyname("vm.vmtotal", &vm, &size, NULL, 0)) {
+        return PyErr_SetFromOSErrnoWithSyscall("sysctlbyname('vm.vmtotal')");
+    }
+
+    return Py_BuildValue("KKKKKKKK",
+        (unsigned long long) total,
+        (unsigned long long) free     * pagesize,
+        (unsigned long long) active   * pagesize,
+        (unsigned long long) inactive * pagesize,
+        (unsigned long long) wired    * pagesize,
+        (unsigned long long) cached   * pagesize,
+        (unsigned long long) buffers,
+        (unsigned long long) (vm.t_vmshr + vm.t_rmshr) * pagesize  // shared
+    );
+}
+
+
+PyObject *
+psutil_swap_mem(PyObject *self, PyObject *args) {
+    // Return swap memory stats (see 'swapinfo' cmdline tool)
+    kvm_t *kd;
+    struct kvm_swap kvmsw[1];
+    unsigned int swapin, swapout, nodein, nodeout;
+    size_t size = sizeof(unsigned int);
+    long pagesize = psutil_getpagesize();
+
+    kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open failed");
+    if (kd == NULL) {
+        PyErr_SetString(PyExc_RuntimeError, "kvm_open() syscall failed");
+        return NULL;
+    }
+
+    if (kvm_getswapinfo(kd, kvmsw, 1, 0) < 0) {
+        kvm_close(kd);
+        PyErr_SetString(PyExc_RuntimeError,
+                        "kvm_getswapinfo() syscall failed");
+        return NULL;
+    }
+
+    kvm_close(kd);
+
+    if (sysctlbyname("vm.stats.vm.v_swapin", &swapin, &size, NULL, 0) == -1) {
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('vm.stats.vm.v_swapin)'");
+    }
+    if (sysctlbyname("vm.stats.vm.v_swapout", &swapout, &size, NULL, 0) == -1){
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('vm.stats.vm.v_swapout)'");
+    }
+    if (sysctlbyname("vm.stats.vm.v_vnodein", &nodein, &size, NULL, 0) == -1) {
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('vm.stats.vm.v_vnodein)'");
+    }
+    if (sysctlbyname("vm.stats.vm.v_vnodeout", &nodeout, &size, NULL, 0) == -1) {
+        return PyErr_SetFromOSErrnoWithSyscall(
+            "sysctlbyname('vm.stats.vm.v_vnodeout)'");
+    }
+
+    return Py_BuildValue(
+        "(KKKII)",
+        (unsigned long long)kvmsw[0].ksw_total * pagesize,  // total
+        (unsigned long long)kvmsw[0].ksw_used * pagesize,  // used
+        (unsigned long long)kvmsw[0].ksw_total * pagesize - // free
+                                kvmsw[0].ksw_used * pagesize,
+        swapin + swapout,  // swap in
+        nodein + nodeout  // swap out
+    );
+}
+
diff --git psutil/arch/dragonfly/mem.h psutil/arch/dragonfly/mem.h
new file mode 100644
index 00000000..e7dcfc57
--- /dev/null
+++ psutil/arch/dragonfly/mem.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <Python.h>
+
+PyObject *psutil_swap_mem(PyObject* self, PyObject* args);
+PyObject *psutil_virtual_mem(PyObject* self, PyObject* args);
diff --git psutil/arch/dragonfly/proc.c psutil/arch/dragonfly/proc.c
new file mode 100644
index 00000000..d06eb65f
--- /dev/null
+++ psutil/arch/dragonfly/proc.c
@@ -0,0 +1,489 @@
+/*
+ * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <Python.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <devstat.h>
+#include <libutil.h>  // process open files, shared libs (kinfo_getvmmap), cwd
+
+#include "../../_psutil_common.h"
+#include "../../_psutil_posix.h"
+
+#define PSUTIL_TV2DOUBLE(t)    ((t).tv_sec + (t).tv_usec / 1000000.0)
+
+// ============================================================================
+// Utility functions
+// ============================================================================
+
+
+int
+psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) {
+    // Fills a kinfo_proc struct based on process pid.
+    int mib[4];
+    size_t size;
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_PID;
+    mib[3] = pid;
+
+    size = sizeof(struct kinfo_proc);
+    if (sysctl((int *)mib, 4, proc, &size, NULL, 0) == -1) {
+        PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROC_PID)");
+        return -1;
+    }
+
+    // sysctl stores 0 in the size if we can't find the process information.
+    if (size == 0) {
+        NoSuchProcess("sysctl (size = 0)");
+        return -1;
+    }
+    return 0;
+}
+
+
+// remove spaces from string
+static void psutil_remove_spaces(char *str) {
+    char *p1 = str;
+    char *p2 = str;
+    do
+        while (*p2 == ' ')
+            p2++;
+    while ((*p1++ = *p2++));
+}
+
+
+// ============================================================================
+// APIS
+// ============================================================================
+
+int
+psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) {
+    // Returns a list of all BSD processes on the system.  This routine
+    // allocates the list and puts it in *procList and a count of the
+    // number of entries in *procCount.  You are responsible for freeing
+    // this list. On success returns 0, else 1 with exception set.
+    int err;
+    struct kinfo_proc *buf = NULL;
+    int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
+    size_t length = 0;
+
+    assert(procList != NULL);
+    assert(*procList == NULL);
+    assert(procCount != NULL);
+
+    // Call sysctl with a NULL buffer in order to get buffer length.
+    err = sysctl(name, 3, NULL, &length, NULL, 0);
+    if (err == -1) {
+        PyErr_SetFromOSErrnoWithSyscall("sysctl (null buffer)");
+        return 1;
+    }
+
+    // Allocate an appropriately sized buffer based on the results
+    // from the previous call.
+    buf = malloc(length);
+    if (buf == NULL) {
+        PyErr_NoMemory();
+        return 1;
+    }
+
+    // Call sysctl again with the new buffer.
+    err = sysctl(name, 3, buf, &length, NULL, 0);
+    if (err == -1) {
+        PyErr_SetFromOSErrnoWithSyscall("sysctl");
+        free(buf);
+        return 1;
+    }
+
+    *procList = buf;
+    *procCount = length / sizeof(struct kinfo_proc);
+    return 0;
+}
+
+
+/*
+ * XXX no longer used; it probably makese sense to remove it.
+ * Borrowed from psi Python System Information project
+ *
+ * Get command arguments and environment variables.
+ *
+ * Based on code from ps.
+ *
+ * Returns:
+ *      0 for success;
+ *      -1 for failure (Exception raised);
+ *      1 for insufficient privileges.
+ */
+static char
+*psutil_get_cmd_args(pid_t pid, size_t *argsize) {
+    int mib[4];
+    int argmax;
+    size_t size = sizeof(argmax);
+    char *procargs = NULL;
+
+    // Get the maximum process arguments size.
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_ARGMAX;
+
+    size = sizeof(argmax);
+    if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1)
+        return NULL;
+
+    // Allocate space for the arguments.
+    procargs = (char *)malloc(argmax);
+    if (procargs == NULL) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+
+    // Make a sysctl() call to get the raw argument space of the process.
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_ARGS;
+    mib[3] = pid;
+
+    size = argmax;
+    if (sysctl(mib, 4, procargs, &size, NULL, 0) == -1) {
+        free(procargs);
+        PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROC_ARGS)");
+        return NULL;
+    }
+
+    // return string and set the length of arguments
+    *argsize = size;
+    return procargs;
+}
+
+
+// returns the command line as a python list object
+PyObject *
+psutil_get_cmdline(pid_t pid) {
+    char *argstr = NULL;
+    size_t pos = 0;
+    size_t argsize = 0;
+    PyObject *py_retlist = Py_BuildValue("[]");
+    PyObject *py_arg = NULL;
+
+    if (pid < 0)
+        return py_retlist;
+    argstr = psutil_get_cmd_args(pid, &argsize);
+    if (argstr == NULL)
+        goto error;
+
+    // args are returned as a flattened string with \0 separators between
+    // arguments add each string to the list then step forward to the next
+    // separator
+    if (argsize > 0) {
+        while (pos < argsize) {
+            py_arg = PyUnicode_DecodeFSDefault(&argstr[pos]);
+            if (!py_arg)
+                goto error;
+            if (PyList_Append(py_retlist, py_arg))
+                goto error;
+            Py_DECREF(py_arg);
+            pos = pos + strlen(&argstr[pos]) + 1;
+        }
+    }
+
+    free(argstr);
+    return py_retlist;
+
+error:
+    Py_XDECREF(py_arg);
+    Py_DECREF(py_retlist);
+    if (argstr != NULL)
+        free(argstr);
+    return NULL;
+}
+
+
+/*
+ * Return process pathname executable.
+ * Thanks to Robert N. M. Watson:
+ * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_bin.c?v=8-CURRENT
+ */
+PyObject *
+psutil_proc_exe(PyObject *self, PyObject *args) {
+    pid_t pid;
+    char pathname[PATH_MAX];
+    int error;
+    int mib[4];
+    int ret;
+    size_t size;
+
+    if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
+        return NULL;
+
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_PATHNAME;
+    mib[3] = pid;
+
+    size = sizeof(pathname);
+    error = sysctl(mib, 4, pathname, &size, NULL, 0);
+    if (error == -1) {
+        // see: https://github.com/giampaolo/psutil/issues/907
+        if (errno == ENOENT) {
+            return PyUnicode_DecodeFSDefault("");
+        }
+        else {
+            return \
+                PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROC_PATHNAME)");
+        }
+    }
+    if (size == 0 || strlen(pathname) == 0) {
+        ret = psutil_pid_exists(pid);
+        if (ret == -1)
+            return NULL;
+        else if (ret == 0)
+            return NoSuchProcess("psutil_pid_exists -> 0");
+        else
+            strcpy(pathname, "");
+    }
+
+    return PyUnicode_DecodeFSDefault(pathname);
+}
+
+
+PyObject *
+psutil_proc_num_threads(PyObject *self, PyObject *args) {
+    // Return number of threads used by process as a Python integer.
+    pid_t pid;
+    struct kinfo_proc kp;
+    if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
+        return NULL;
+    if (psutil_kinfo_proc(pid, &kp) == -1)
+        return NULL;
+    return Py_BuildValue("l", (long)kp.kp_nthreads);
+}
+
+
+PyObject *
+psutil_proc_threads(PyObject *self, PyObject *args) {
+    // Retrieves all threads used by process returning a list of tuples
+    // including thread id, user time and system time.
+    // Thanks to Robert N. M. Watson:
+    // http://code.metager.de/source/xref/freebsd/usr.bin/procstat/
+    //     procstat_threads.c
+    pid_t pid;
+    int mib[4];
+    struct kinfo_proc *kip = NULL;
+    struct kinfo_proc *kipp = NULL;
+    int error;
+    unsigned int i;
+    size_t size;
+    PyObject *py_retlist = PyList_New(0);
+    PyObject *py_tuple = NULL;
+
+    if (py_retlist == NULL)
+        return NULL;
+    if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
+        goto error;
+
+    // we need to re-query for thread information, so don't use *kipp
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_PID | KERN_PROC_FLAG_LWP;
+    mib[3] = pid;
+
+    size = 0;
+    error = sysctl(mib, 4, NULL, &size, NULL, 0);
+    if (error == -1) {
+        PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROC_INC_THREAD)");
+        goto error;
+    }
+    if (size == 0) {
+        NoSuchProcess("sysctl (size = 0)");
+        goto error;
+    }
+
+    kip = malloc(size);
+    if (kip == NULL) {
+        PyErr_NoMemory();
+        goto error;
+    }
+
+    error = sysctl(mib, 4, kip, &size, NULL, 0);
+    if (error == -1) {
+        PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROC_INC_THREAD)");
+        goto error;
+    }
+    if (size == 0) {
+        NoSuchProcess("sysctl (size = 0)");
+        goto error;
+    }
+
+    for (i = 0; i < size / sizeof(*kipp); i++) {
+        kipp = &kip[i];
+        py_tuple = Py_BuildValue("Idd",
+                                 kipp->kp_lwp.kl_tid,
+                                 PSUTIL_TV2DOUBLE(kipp->kp_lwp.kl_ru.ru_utime),
+                                 PSUTIL_TV2DOUBLE(kipp->kp_lwp.kl_ru.ru_stime));
+        if (py_tuple == NULL)
+            goto error;
+        if (PyList_Append(py_retlist, py_tuple))
+            goto error;
+        Py_DECREF(py_tuple);
+    }
+    free(kip);
+    return py_retlist;
+
+error:
+    Py_XDECREF(py_tuple);
+    Py_DECREF(py_retlist);
+    if (kip != NULL)
+        free(kip);
+    return NULL;
+}
+
+PyObject *
+psutil_proc_cwd(PyObject *self, PyObject *args) {
+    size_t size;
+    pid_t pid;
+    int error;
+    char *cwd;
+    int mib[4];
+    PyObject *py_path = NULL;
+
+    int i, cnt;
+
+    if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
+	    goto out;
+
+    // Allocate space for the arguments.
+    cwd = (char *)malloc(PATH_MAX);
+    if (cwd == NULL) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_CWD;
+    mib[3] = pid;
+    error = sysctl(mib, 4, cwd, &size, NULL, 0);
+    if (error == -1) {
+	    free(cwd);
+	    PyErr_SetFromOSErrnoWithSyscall("sysctl(KERN_PROC_CWD)");
+	    return NULL;
+    }
+
+    py_path = PyUnicode_DecodeFSDefault(cwd);
+    if (!py_path)
+	    goto out;
+
+    return py_path;
+
+out:
+    Py_XDECREF(py_path);
+    if (cwd != NULL)
+        free(cwd);
+    return NULL;
+}
+
+PyObject*
+psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args) {
+    // Get process CPU affinity.
+    // Reference:
+    // http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c
+    pid_t pid;
+    int ret;
+    int i;
+    cpu_set_t mask;
+    PyObject* py_retlist;
+    PyObject* py_cpu_num;
+
+    CPU_ZERO(&mask);
+
+    if (!PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
+        return NULL;
+    ret = sched_getaffinity(pid, sizeof(mask), &mask);
+    if (ret != 0)
+        return PyErr_SetFromErrno(PyExc_OSError);
+
+    py_retlist = PyList_New(0);
+    if (py_retlist == NULL)
+        return NULL;
+
+    for (i = 0; i < CPU_SETSIZE; i++) {
+        if (CPU_ISSET(i, &mask)) {
+            py_cpu_num = Py_BuildValue("i", i);
+            if (py_cpu_num == NULL)
+                goto error;
+            if (PyList_Append(py_retlist, py_cpu_num))
+                goto error;
+        }
+    }
+
+    return py_retlist;
+
+error:
+    Py_XDECREF(py_cpu_num);
+    Py_DECREF(py_retlist);
+    return NULL;
+}
+
+
+PyObject *
+psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
+    // Set process CPU affinity.
+    // Reference:
+    // http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c
+    pid_t pid;
+    int i;
+    int seq_len;
+    int ret;
+    cpu_set_t cpu_set;
+    PyObject *py_cpu_set;
+    PyObject *py_cpu_seq = NULL;
+
+    if (!PyArg_ParseTuple(args, _Py_PARSE_PID "O", &pid, &py_cpu_set))
+        return NULL;
+
+    py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer");
+    if (!py_cpu_seq)
+        return NULL;
+    seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq);
+
+    // calculate the mask
+    CPU_ZERO(&cpu_set);
+    for (i = 0; i < seq_len; i++) {
+        PyObject *item = PySequence_Fast_GET_ITEM(py_cpu_seq, i);
+#if PY_MAJOR_VERSION >= 3
+        long value = PyLong_AsLong(item);
+#else
+        long value = PyInt_AsLong(item);
+#endif
+        if (value == -1 || PyErr_Occurred())
+            goto error;
+        CPU_SET(value, &cpu_set);
+    }
+
+    // set affinity
+    ret = sched_setaffinity(pid, sizeof(cpu_set), &cpu_set);
+    if (ret != 0) {
+        PyErr_SetFromErrno(PyExc_OSError);
+        goto error;
+    }
+
+    Py_DECREF(py_cpu_seq);
+    Py_RETURN_NONE;
+
+error:
+    if (py_cpu_seq != NULL)
+        Py_DECREF(py_cpu_seq);
+    return NULL;
+}
diff --git psutil/arch/dragonfly/proc.h psutil/arch/dragonfly/proc.h
new file mode 100644
index 00000000..9c16f3cb
--- /dev/null
+++ psutil/arch/dragonfly/proc.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <Python.h>
+
+typedef struct kinfo_proc kinfo_proc;
+
+int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount);
+int psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc);
+
+PyObject* psutil_get_cmdline(long pid);
+PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args);
+PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args);
+PyObject* psutil_proc_cwd(PyObject* self, PyObject* args);
+PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
+PyObject* psutil_proc_getrlimit(PyObject* self, PyObject* args);
+PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args);
+PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args);
+PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args);
+PyObject* psutil_proc_setrlimit(PyObject* self, PyObject* args);
+PyObject* psutil_proc_threads(PyObject* self, PyObject* args);
diff --git psutil/arch/dragonfly/proc_socks.h psutil/arch/dragonfly/proc_socks.h
new file mode 100644
index 00000000..a7996b10
--- /dev/null
+++ psutil/arch/dragonfly/proc_socks.h
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <Python.h>
+
+PyObject* psutil_proc_connections(PyObject* self, PyObject* args);
diff --git psutil/arch/dragonfly/sensors.c psutil/arch/dragonfly/sensors.c
new file mode 100644
index 00000000..722e0930
--- /dev/null
+++ psutil/arch/dragonfly/sensors.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+Original code was refactored and moved from psutil/arch/freebsd/specific.c
+For reference, here's the git history with original(ish) implementations:
+- sensors_battery(): 022cf0a05d34f4274269d4f8002ee95b9f3e32d2
+- sensors_cpu_temperature(): bb5d032be76980a9e110f03f1203bd35fa85a793
+  (patch by Alex Manuskin)
+*/
+
+
+#include <Python.h>
+#include <sys/sysctl.h>
+
+#include "../../_psutil_common.h"
+#include "../../_psutil_posix.h"
+
+
+#define DECIKELVIN_2_CELCIUS(t) (t - 2731) / 10
+
+
+PyObject *
+psutil_sensors_battery(PyObject *self, PyObject *args) {
+    int percent;
+    int minsleft;
+    int power_plugged;
+    size_t size = sizeof(percent);
+
+    if (sysctlbyname("hw.acpi.battery.life", &percent, &size, NULL, 0))
+        goto error;
+    if (sysctlbyname("hw.acpi.battery.time", &minsleft, &size, NULL, 0))
+        goto error;
+    if (sysctlbyname("hw.acpi.acline", &power_plugged, &size, NULL, 0))
+        goto error;
+    return Py_BuildValue("iii", percent, minsleft, power_plugged);
+
+error:
+    // see: https://github.com/giampaolo/psutil/issues/1074
+    if (errno == ENOENT)
+        PyErr_SetString(PyExc_NotImplementedError, "no battery");
+    else
+        PyErr_SetFromErrno(PyExc_OSError);
+    return NULL;
+}
+
+
+// Return temperature information for a given CPU core number.
+PyObject *
+psutil_sensors_cpu_temperature(PyObject *self, PyObject *args) {
+    int current;
+    int tjmax;
+    int core;
+    char sensor[26];
+    size_t size = sizeof(current);
+
+    if (! PyArg_ParseTuple(args, "i", &core))
+        return NULL;
+    sprintf(sensor, "hw.sensors.cpu%d.temp0", core);
+    if (sysctlbyname(sensor, &current, &size, NULL, 0))
+        goto error;
+    current = DECIKELVIN_2_CELCIUS(current);
+
+    // Return -273 in case of faliure.
+    sprintf(sensor, "dev.cpu.%d.coretemp.tjmax", core);
+    if (sysctlbyname(sensor, &tjmax, &size, NULL, 0))
+        tjmax = 0;
+    tjmax = DECIKELVIN_2_CELCIUS(tjmax);
+
+    return Py_BuildValue("ii", current, tjmax);
+
+error:
+    if (errno == ENOENT)
+        PyErr_SetString(PyExc_NotImplementedError, "no temperature sensors");
+    else
+        PyErr_SetFromErrno(PyExc_OSError);
+    return NULL;
+}
+
diff --git psutil/arch/dragonfly/sensors.h psutil/arch/dragonfly/sensors.h
new file mode 100644
index 00000000..e5c4107b
--- /dev/null
+++ psutil/arch/dragonfly/sensors.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <Python.h>
+
+PyObject* psutil_sensors_battery(PyObject* self, PyObject* args);
+PyObject* psutil_sensors_cpu_temperature(PyObject* self, PyObject* args);
diff --git psutil/arch/dragonfly/sys_socks.c psutil/arch/dragonfly/sys_socks.c
new file mode 100644
index 00000000..f2ea848e
--- /dev/null
+++ psutil/arch/dragonfly/sys_socks.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2009, Giampaolo Rodola'.
+ * All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Copyright (c) 2005 Joerg Sonnenberger <joerg@bec.de>.  All rights reserved.
+ * Copyright (c) 2002 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ */
+
+#include <Python.h>
+#include <sys/user.h>
+#include <sys/file.h>
+#include <sys/socketvar.h>    // for struct xsocket
+#include <sys/un.h>
+#include <sys/unpcb.h>
+#include <sys/sysctl.h>
+#include <netinet/in.h>   // for xinpcb struct
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/tcp_var.h>   // for struct xtcpcb
+#include <arpa/inet.h>         // for inet_ntop()
+#include <kinfo.h>             /* For kinfo_get_files */
+
+#include "../../_psutil_common.h"
+#include "../../_psutil_posix.h"
+
+static struct kinfo_file *psutil_xfiles;
+static size_t psutil_nxfiles;
+
+#define HASHSIZE 1009
+static struct sock *sockhash[HASHSIZE];
+
+int
+psutil_populate_xfiles(void) {
+	if (kinfo_get_files(&psutil_xfiles, &psutil_nxfiles)) {
+		if (errno == ENOMEM)
+			PyErr_NoMemory();
+		else if (errno != ENOMEM)
+			PyErr_SetFromErrno(0);
+
+		return 0;
+	}
+
+	return 1;	/* Success */
+}
+
+struct kinfo_file *
+psutil_get_file_from_sock(void *sock) {
+	struct kinfo_file *xf;
+	int n;
+
+	for (xf = psutil_xfiles, n = 0; n < (int)psutil_nxfiles; ++n, ++xf) {
+		if (xf->f_data == sock)
+			return xf;
+	}
+	return NULL;
+}
+
+int psutil_gather_inet(int proto, PyObject *py_retlist)
+{
+	void *so_begin, *so_end;
+	struct xinpcb *xip;
+	struct xtcpcb *xtp;
+	struct inpcb *inp;
+	struct xsocket *so;
+	struct sock *sock;
+	const char *varname, *protoname;
+	size_t len;
+	void *buf;
+	int type;
+
+	PyObject *py_tuple = NULL;
+	PyObject *py_laddr = NULL;
+	PyObject *py_raddr = NULL;
+
+	switch (proto) {
+	case IPPROTO_TCP:
+		varname = "net.inet.tcp.pcblist";
+		protoname = "tcp";
+		break;
+	case IPPROTO_UDP:
+		varname = "net.inet.udp.pcblist";
+		protoname = "udp";
+		break;
+	default:
+		abort();
+	}
+
+	buf = NULL;
+	len = 0;
+
+	if (sysctlbyname(varname, NULL, &len, NULL, 0)) {
+		PyErr_SetFromErrno(0);
+		return 0;
+	}
+	if ((buf = malloc(len)) == NULL) {
+		PyErr_NoMemory();
+		return 0;
+	}
+	if (sysctlbyname(varname, buf, &len, NULL, 0)) {
+		PyErr_SetFromErrno(0);
+		return 0;
+	}
+
+	so_begin = buf;
+	so_end = (uint8_t *)buf + len;
+
+	for (so_begin = buf, so_end = (uint8_t *)so_begin + len;
+	     (uint8_t *)so_begin + sizeof(size_t) < (uint8_t *)so_end &&
+	     (uint8_t *)so_begin + *(size_t *)so_begin <= (uint8_t *)so_end;
+	     so_begin = (uint8_t *)so_begin + *(size_t *)so_begin) {
+		struct kinfo_file *xf;
+		int lport, rport, status, family;
+
+		switch (proto) {
+		case IPPROTO_TCP:
+			xtp = (struct xtcpcb *)so_begin;
+			if (xtp->xt_len != sizeof *xtp) {
+				PyErr_Format(PyExc_RuntimeError,
+				    "struct xtcpcb size mismatch");
+				goto error;
+			}
+			inp = &xtp->xt_inp;
+			so = &xtp->xt_socket;
+			break;
+		case IPPROTO_UDP:
+			xip = (struct xinpcb *)so_begin;
+			if (xip->xi_len != sizeof *xip) {
+				PyErr_Format(PyExc_RuntimeError,
+				    "struct xtcpcb size mismatch");
+				goto error;
+			}
+			inp = &xip->xi_inp;
+			so = &xip->xi_socket;
+			break;
+		default:
+			PyErr_Format(PyExc_RuntimeError, "invalid proto");
+			goto error;
+		}
+
+		char lip[200], rip[200];
+
+		xf = psutil_get_file_from_sock(so->xso_so);
+		if (xf == NULL)
+			continue;
+
+		lport = ntohs(inp->inp_lport);
+		rport = ntohs(inp->inp_fport);
+
+		if (INP_ISIPV4(inp)) {
+			family = AF_INET;
+			inet_ntop(AF_INET, &inp->inp_laddr.s_addr, lip, sizeof(lip));
+			inet_ntop(AF_INET, &inp->inp_faddr.s_addr, rip, sizeof(rip));
+		}
+		else if (INP_ISIPV6(inp)) {
+			family = AF_INET6;
+			inet_ntop(AF_INET6, &inp->in6p_laddr.s6_addr, lip, sizeof(lip));
+			inet_ntop(AF_INET6, &inp->in6p_faddr.s6_addr, rip, sizeof(rip));
+		}
+
+		// construct python tuple/list
+		py_laddr = Py_BuildValue("(si)", lip, lport);
+		if (!py_laddr)
+			goto error;
+		if (rport != 0)
+			py_raddr = Py_BuildValue("(si)", rip, rport);
+		else
+			py_raddr = Py_BuildValue("()");
+		if (!py_raddr)
+			goto error;
+		py_tuple = Py_BuildValue(
+			"iiiNNi" _Py_PARSE_PID,
+			    xf->f_fd, // fd
+			    family,    // family
+			    type,      // type
+			    py_laddr,  // laddr
+			    py_raddr,  // raddr
+			    status,    // status
+			    xf->f_pid // pid
+			);
+		if (!py_tuple)
+			goto error;
+		if (PyList_Append(py_retlist, py_tuple))
+			goto error;
+		Py_CLEAR(py_tuple);
+
+	}
+
+error:
+    Py_XDECREF(py_tuple);
+    Py_XDECREF(py_laddr);
+    Py_XDECREF(py_raddr);
+    free(buf);
+    return 0;
+}
+
+
+int psutil_gather_unix(int proto, PyObject *py_retlist) {
+	void *so_begin, *so_end;
+	struct xunpcb *xup;
+	const char *varname, *protoname;
+	size_t len;
+	void *buf;
+	struct sockaddr_un *sun;
+	char path[PATH_MAX];
+
+	PyObject *py_tuple = NULL;
+	PyObject *py_lpath = NULL;
+
+	switch (proto) {
+        case SOCK_STREAM:
+		varname = "net.local.stream.pcblist";
+		protoname = "stream";
+		break;
+        case SOCK_DGRAM:
+		varname = "net.local.dgram.pcblist";
+		protoname = "dgram";
+		break;
+	}
+	buf = NULL;
+	len = 0;
+
+	if (sysctlbyname(varname, NULL, &len, NULL, 0)) {
+		PyErr_SetFromErrno(0);
+		return 0;
+	}
+	if ((buf = malloc(len)) == NULL) {
+		PyErr_NoMemory();
+		return 0;
+	}
+	if (sysctlbyname(varname, buf, &len, NULL, 0)) {
+		PyErr_SetFromErrno(0);
+		return 0;
+	}
+
+	for (so_begin = buf, so_end = (uint8_t *)buf + len;
+	     (uint8_t *)so_begin + sizeof(size_t) < (uint8_t *)so_end &&
+	     (uint8_t *)so_begin + *(size_t *)so_begin <= (uint8_t *)so_end;
+	     so_begin = (uint8_t *)so_begin + *(size_t *)so_begin) {
+		struct kinfo_file *xf;
+
+		xup = so_begin;
+		if (xup->xu_len != sizeof *xup) {
+			PyErr_Format(PyExc_RuntimeError,
+			    "struct xtcpcb size mismatch");
+			goto error;
+		}
+
+		xf = psutil_get_file_from_sock(xup->xu_socket.xso_so);
+		if (xf == NULL)
+			continue;
+
+		sun = (struct sockaddr_un *)&xup->xu_addr;
+		snprintf(path, sizeof(path), "%.*s",
+		    (int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))),
+		    sun->sun_path);
+		py_lpath = PyUnicode_DecodeFSDefault(path);
+		if (! py_lpath)
+			goto error;
+
+		py_tuple = Py_BuildValue("(iiiOsii)",
+		    xf->f_fd,         // fd
+		    AF_UNIX,           // family
+		    proto,             // type
+		    py_lpath,          // lpath
+		    "",                // rath
+		    PSUTIL_CONN_NONE,  // status
+		    xf->f_pid);       // pid
+		if (!py_tuple)
+			goto error;
+		if (PyList_Append(py_retlist, py_tuple))
+			goto error;
+		Py_DECREF(py_lpath);
+		Py_DECREF(py_tuple);
+	}
+
+	free(buf);
+	return 1;
+
+error:
+	Py_XDECREF(py_tuple);
+	Py_XDECREF(py_lpath);
+	free(buf);
+	return 0;
+}
+
+PyObject*
+psutil_net_connections(PyObject* self, PyObject* args) {
+    // Return system-wide open connections.
+    PyObject *py_retlist = PyList_New(0);
+
+    if (py_retlist == NULL)
+        return NULL;
+    if (psutil_populate_xfiles() != 1)
+        goto error;
+    if (psutil_gather_inet(IPPROTO_TCP, py_retlist) == 0)
+        goto error;
+    if (psutil_gather_inet(IPPROTO_UDP, py_retlist) == 0)
+        goto error;
+    if (psutil_gather_unix(SOCK_STREAM, py_retlist) == 0)
+       goto error;
+    if (psutil_gather_unix(SOCK_DGRAM, py_retlist) == 0)
+        goto error;
+
+    free(psutil_xfiles);
+    return py_retlist;
+
+error:
+    Py_DECREF(py_retlist);
+    free(psutil_xfiles);
+    return NULL;
+}
diff --git psutil/arch/dragonfly/sys_socks.h psutil/arch/dragonfly/sys_socks.h
new file mode 100644
index 00000000..75247926
--- /dev/null
+++ psutil/arch/dragonfly/sys_socks.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2009, Giampaolo Rodola'.
+ * All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <Python.h>
+
+PyObject* psutil_net_connections(PyObject* self, PyObject* args);
diff --git psutil/tests/test_system.py psutil/tests/test_system.py
index d6b7a21a..75532f87 100755
--- psutil/tests/test_system.py
+++ psutil/tests/test_system.py
@@ -22,6 +22,7 @@ import psutil
 from psutil import AIX
 from psutil import BSD
 from psutil import FREEBSD
+from psutil import DRAGONFLY
 from psutil import LINUX
 from psutil import MACOS
 from psutil import NETBSD
@@ -650,7 +651,7 @@ class TestDiskAPIs(PsutilTestCase):
             self.assertEqual(nt[1], nt.write_count)
             self.assertEqual(nt[2], nt.read_bytes)
             self.assertEqual(nt[3], nt.write_bytes)
-            if not (OPENBSD or NETBSD):
+            if not (OPENBSD or NETBSD or DRAGONFLY):
                 self.assertEqual(nt[4], nt.read_time)
                 self.assertEqual(nt[5], nt.write_time)
                 if LINUX:
diff --git setup.py setup.py
index 0f6716b3..ca0ad0b6 100755
--- setup.py
+++ setup.py
@@ -40,6 +40,7 @@ sys.path.insert(0, os.path.join(HERE, "psutil"))
 from _common import AIX  # NOQA
 from _common import BSD  # NOQA
 from _common import FREEBSD  # NOQA
+from _common import DRAGONFLY  # NOQA
 from _common import LINUX  # NOQA
 from _common import MACOS  # NOQA
 from _common import NETBSD  # NOQA
@@ -242,6 +243,22 @@ elif NETBSD:
         define_macros=macros,
         libraries=["kvm"])
 
+elif DRAGONFLY:
+    macros.append(("PSUTIL_DRAGONFLY", 1))
+    ext = Extension(
+        'psutil._psutil_bsd',
+        sources=sources + [
+            'psutil/_psutil_bsd.c',
+            'psutil/arch/dragonfly/cpu.c',
+            'psutil/arch/dragonfly/mem.c',
+            'psutil/arch/dragonfly/disk.c',
+            'psutil/arch/dragonfly/sensors.c',
+            'psutil/arch/dragonfly/proc.c',
+            'psutil/arch/dragonfly/sys_socks.c'
+        ],
+        define_macros=macros,
+        libraries=["kvm", "kinfo", "devstat"])
+
 elif LINUX:
     def get_ethtool_macro():
         # see: https://github.com/giampaolo/psutil/issues/659
@@ -385,6 +402,7 @@ def main():
             'Operating System :: POSIX :: BSD :: FreeBSD',
             'Operating System :: POSIX :: BSD :: NetBSD',
             'Operating System :: POSIX :: BSD :: OpenBSD',
+            'Operating System :: POSIX :: BSD :: DragonFly BSD',
             'Operating System :: POSIX :: BSD',
             'Operating System :: POSIX :: Linux',
             'Operating System :: POSIX :: SunOS/Solaris',
@@ -431,8 +449,8 @@ def main():
             elif MACOS:
                 print(hilite("XCode (https://developer.apple.com/xcode/) "
                              "is not installed"), color="red", file=sys.stderr)
-            elif FREEBSD:
-                if which('pkg'):
+            elif FREEBSD or DRAGONFLY:
+                if which('pkg'):       # FreeBSD/DragonFly
                     missdeps("pkg install gcc python%s" % py3)
                 elif which('mport'):   # MidnightBSD
                     missdeps("mport install gcc python%s" % py3)
