Ticket #11852: 0001-Replace-BTimeSource-array-based-slave-nodes-manageme.patch

File 0001-Replace-BTimeSource-array-based-slave-nodes-manageme.patch, 18.4 KB (added by Barrett, 9 years ago)

Compared to the previous patch this add better error checking when adding/removing a slave node.

  • src/kits/media/TimeSource.cpp

    From dbf6fcaa4f4eb34c6c5516a89a4184c43a4dd762 Mon Sep 17 00:00:00 2001
    From: Dario Casalinuovo <b.vitruvio@gmail.com>
    Date: Sat, 14 Feb 2015 15:26:05 +0100
    Subject: [PATCH] Replace BTimeSource array-based slave nodes management with a
     new one based on BObjectList. Solve TODO making SlaveNodes members private.
     General cleanup and style fixes to improve readability of code.
    
    ---
     src/kits/media/TimeSource.cpp | 329 +++++++++++++++++++++++++-----------------
     1 file changed, 198 insertions(+), 131 deletions(-)
    
    diff --git a/src/kits/media/TimeSource.cpp b/src/kits/media/TimeSource.cpp
    index dae0244..ce302f3 100644
    a b  
    11/*
    2  * Copyright 2002-2012, Haiku. All Rights Reserved.
    3  * This file may be used under the terms of the MIT License.
     2 * Copyright 2002-2015 Haiku, Inc. All rights reserved.
     3 * Distributed under the terms of the MIT License.
    44 *
    5  * Author: Marcus Overhagen
     5 * Authors:
     6 *      Marcus Overhagen
     7 *      Dario Casalinuovo
    68 */
    79
    810
    9 #include <TimeSource.h>
    1011#include <Autolock.h>
     12#include <ObjectList.h>
     13#include <TimeSource.h>
     14
    1115#include <string.h>
     16
    1217#include "debug.h"
    1318#include "DataExchange.h"
    1419#include "ServerInterface.h"
    namespace BPrivate { namespace media {  
    2631
    2732#define _atomic_read(p)     atomic_or((p), 0)
    2833
    29 #define TS_AREA_SIZE        B_PAGE_SIZE     // must be multiple of page size
    30 #define TS_INDEX_COUNT      128             // must be power of two
     34// must be multiple of page size
     35#define TS_AREA_SIZE        B_PAGE_SIZE
     36// must be power of two
     37#define TS_INDEX_COUNT      128
    3138
    32 struct TimeSourceTransmit // sizeof(TimeSourceTransmit) must be <= TS_AREA_SIZE
     39// sizeof(TimeSourceTransmit) must be <= TS_AREA_SIZE
     40struct TimeSourceTransmit
    3341{
    3442    int32 readindex;
    3543    int32 writeindex;
    struct TimeSourceTransmit // sizeof(TimeSourceTransmit) must be <= TS_AREA_SIZE  
    3947    float drift[TS_INDEX_COUNT];
    4048};
    4149
    42 #define SLAVE_NODES_COUNT 300
     50#define MAX_SLAVE_NODES 300
    4351
    44 // XXX TODO: storage for slave nodes uses public data members, this should be changed
    4552
    46 class SlaveNodes
    47 {
     53class SlaveNode {
    4854public:
    49                     SlaveNodes();
    50                     ~SlaveNodes();
     55                            SlaveNode(media_node_id nodeId, port_id nodePort);
     56
     57    media_node_id           NodeId() const;
     58    port_id                 NodePort() const;
     59
     60private:
     61    media_node_id           fNodeId;
     62    port_id                 fNodePort;
     63};
     64
     65
     66SlaveNode::SlaveNode(media_node_id nodeId, port_id nodePort)
     67{
     68    fNodeId = nodeId;
     69    fNodePort = nodePort;
     70}
     71
     72
     73media_node_id
     74SlaveNode::NodeId() const
     75{
     76    return fNodeId;
     77}
     78
     79
     80port_id
     81SlaveNode::NodePort() const
     82{
     83    return fNodePort;
     84}
     85
     86
     87class SlaveNodes : public BLocker
     88{
    5189public:
    52     BLocker *       locker;
    53     int32           count;
    54     media_node_id   node_id[SLAVE_NODES_COUNT];
    55     port_id         node_port[SLAVE_NODES_COUNT];
     90                            SlaveNodes();
     91
     92    int32                   CountSlaves() const;
     93
     94    port_id                 PortAt(int32 index) const;
     95    SlaveNode*              SlaveAt(int32 index) const;
     96
     97    bool                    InsertSlave(const media_node& node);
     98    bool                    RemoveSlave(const media_node& node);
     99
     100private:
     101    BObjectList<SlaveNode>  fSlaveList;
    56102};
    57103
    58104
    59105SlaveNodes::SlaveNodes()
    60106{
    61     locker = new BLocker("BTimeSource SlaveNodes");
    62     count = 0;
    63     memset(node_id, 0, sizeof(node_id));
    64     memset(node_port, 0, sizeof(node_port));
     107    fSlaveList = BObjectList<SlaveNode>(true);
     108}
     109
     110
     111int32
     112SlaveNodes::CountSlaves() const
     113{
     114    return fSlaveList.CountItems();
     115}
     116
     117
     118port_id
     119SlaveNodes::PortAt(int32 index) const
     120{
     121    return SlaveAt(index)->NodePort();
    65122}
    66123
    67124
    68 SlaveNodes::~SlaveNodes()
     125SlaveNode*
     126SlaveNodes::SlaveAt(int32 index) const
    69127{
    70     delete locker;
     128    return fSlaveList.ItemAt(index);
    71129}
    72130
    73131
    74 } }
     132bool
     133SlaveNodes::InsertSlave(const media_node& node)
     134{
     135    return fSlaveList.AddItem(new SlaveNode(node.node, node.port));
     136}
     137
     138
     139bool
     140SlaveNodes::RemoveSlave(const media_node& node)
     141{
     142    for (int i = 0; i < CountSlaves(); i++) {
     143        SlaveNode* slave = fSlaveList.ItemAt(i);
     144        if (slave->NodeId() == node.node
     145            && slave->NodePort() == node.port) {
     146            return fSlaveList.RemoveItemAt(i);
     147        }
     148    }
     149    return false;
     150}
     151
     152
     153} } // namespace BPrivate::media
    75154
    76155
    77156/*************************************************************
    BTimeSource::~BTimeSource()  
    92171
    93172status_t
    94173BTimeSource::SnoozeUntil(bigtime_t performance_time,
    95                          bigtime_t with_latency,
    96                          bool retry_signals)
     174    bigtime_t with_latency, bool retry_signals)
    97175{
    98176    CALLED();
    99177    bigtime_t time;
    BTimeSource::PerformanceTimeFor(bigtime_t real_time)  
    125203    if (GetTime(&last_perf_time, &last_real_time, &last_drift) != B_OK)
    126204        debugger("BTimeSource::PerformanceTimeFor: GetTime failed");
    127205
    128     return last_perf_time + (bigtime_t)((real_time - last_real_time) * last_drift);
     206    return last_perf_time
     207        + (bigtime_t)((real_time - last_real_time) * last_drift);
    129208}
    130209
    131210
    132211bigtime_t
    133212BTimeSource::RealTimeFor(bigtime_t performance_time,
    134                          bigtime_t with_latency)
     213    bigtime_t with_latency)
    135214{
    136215    PRINT(8, "CALLED BTimeSource::RealTimeFor()\n");
    137216
    BTimeSource::RealTimeFor(bigtime_t performance_time,  
    146225    if (GetTime(&last_perf_time, &last_real_time, &last_drift) != B_OK)
    147226        debugger("BTimeSource::RealTimeFor: GetTime failed");
    148227
    149     return last_real_time - with_latency + (bigtime_t)((performance_time - last_perf_time) / last_drift);
     228    return last_real_time - with_latency
     229        + (bigtime_t)((performance_time - last_perf_time) / last_drift);
    150230}
    151231
    152232
    BTimeSource::IsRunning()  
    157237
    158238    bool isrunning;
    159239
     240    // The system time source is always running
    160241    if (fIsRealtime)
    161         isrunning = true; // The system time source is always running :)
     242        isrunning = true;
    162243    else
    163244        isrunning = fBuf ? atomic_add(&fBuf->isrunning, 0) : fStarted;
    164245
    BTimeSource::IsRunning()  
    169250
    170251
    171252status_t
    172 BTimeSource::GetTime(bigtime_t *performance_time,
    173                      bigtime_t *real_time,
    174                      float *drift)
     253BTimeSource::GetTime(bigtime_t* performance_time,
     254    bigtime_t* real_time, float* drift)
    175255{
    176256    PRINT(8, "CALLED BTimeSource::GetTime()\n");
    177257
    BTimeSource::GetTime(bigtime_t *performance_time,  
    180260        *drift = 1.0f;
    181261        return B_OK;
    182262    }
    183 //  if (fBuf == 0) {
    184 //      PRINT(1, "BTimeSource::GetTime: fBuf == 0, name %s, id %ld\n",Name(),ID());
    185 //      *performance_time = *real_time = system_time();
    186 //      *drift = 1.0f;
    187 //      return B_OK;
    188 //  }
    189263
    190264    int32 index;
    191265    index = _atomic_read(&fBuf->readindex);
    BTimeSource::GetTime(bigtime_t *performance_time,  
    194268    *performance_time = fBuf->perftime[index];
    195269    *drift = fBuf->drift[index];
    196270
    197 //  if (*real_time == 0) {
    198 //      *performance_time = *real_time = system_time();
    199 //      *drift = 1.0f;
    200 //      return B_OK;
    201 //  }
    202 //  printf("BTimeSource::GetTime timesource %ld, index %ld, perf %16Ld, real %16Ld, drift %2.2f\n", ID(), index, *performance_time, *real_time, *drift);
    203 
    204271    TRACE_TIMESOURCE("BTimeSource::GetTime     timesource %" B_PRId32
    205272        ", perf %16" B_PRId64 ", real %16" B_PRId64 ", drift %2.2f\n", ID(),
    206273        *performance_time, *real_time, *drift);
    BTimeSource::RealTime()  
    217284
    218285
    219286status_t
    220 BTimeSource::GetStartLatency(bigtime_t *out_latency)
     287BTimeSource::GetStartLatency(bigtime_t* out_latency)
    221288{
    222289    CALLED();
    223290    *out_latency = 0;
    BTimeSource::GetStartLatency(bigtime_t *out_latency)  
    229296 *************************************************************/
    230297
    231298
    232 BTimeSource::BTimeSource() :
     299BTimeSource::BTimeSource()
     300    :
    233301    BMediaNode("This one is never called"),
    234302    fStarted(false),
    235303    fArea(-1),
    BTimeSource::BTimeSource() :  
    239307{
    240308    CALLED();
    241309    AddNodeKind(B_TIME_SOURCE);
    242 //  printf("##### BTimeSource::BTimeSource() name %s, id %ld\n", Name(), ID());
    243 
    244310    // This constructor is only called by real time sources that inherit
    245311    // BTimeSource. We create the communication area in FinishCreate(),
    246312    // since we don't have a correct ID() until this node is registered.
    BTimeSource::BTimeSource() :  
    248314
    249315
    250316status_t
    251 BTimeSource::HandleMessage(int32 message,
    252                            const void *rawdata,
    253                            size_t size)
     317BTimeSource::HandleMessage(int32 message, const void* rawdata,
     318    size_t size)
    254319{
    255320    PRINT(4, "BTimeSource::HandleMessage %#" B_PRIx32 ", node %" B_PRId32 "\n",
    256321        message, fNodeID);
    BTimeSource::HandleMessage(int32 message,  
    258323    switch (message) {
    259324        case TIMESOURCE_OP:
    260325        {
    261             const time_source_op_info *data = static_cast<const time_source_op_info *>(rawdata);
     326            const time_source_op_info* data
     327                = static_cast<const time_source_op_info*>(rawdata);
    262328
    263329            status_t result;
    264330            result = TimeSourceOp(*data, NULL);
    BTimeSource::HandleMessage(int32 message,  
    285351
    286352        case TIMESOURCE_ADD_SLAVE_NODE:
    287353        {
    288             const timesource_add_slave_node_command *data = static_cast<const timesource_add_slave_node_command *>(rawdata);
     354            const timesource_add_slave_node_command* data
     355                = static_cast<const timesource_add_slave_node_command*>(rawdata);
    289356            DirectAddMe(data->node);
    290357            return B_OK;
    291358        }
    292359
    293360        case TIMESOURCE_REMOVE_SLAVE_NODE:
    294361        {
    295             const timesource_remove_slave_node_command *data = static_cast<const timesource_remove_slave_node_command *>(rawdata);
     362            const timesource_remove_slave_node_command* data
     363                = static_cast<const timesource_remove_slave_node_command*>(rawdata);
    296364            DirectRemoveMe(data->node);
    297365            return B_OK;
    298366        }
    299367
    300368        case TIMESOURCE_GET_START_LATENCY:
    301369        {
    302             const timesource_get_start_latency_request *request = static_cast<const timesource_get_start_latency_request *>(rawdata);
     370            const timesource_get_start_latency_request* request
     371                = static_cast<const timesource_get_start_latency_request*>(rawdata);
    303372            timesource_get_start_latency_reply reply;
    304373            rv = GetStartLatency(&reply.start_latency);
    305374            request->SendReply(rv, &reply, sizeof(reply));
    BTimeSource::HandleMessage(int32 message,  
    312381
    313382void
    314383BTimeSource::PublishTime(bigtime_t performance_time,
    315                          bigtime_t real_time,
    316                          float drift)
     384    bigtime_t real_time, float drift)
    317385{
    318386    TRACE_TIMESOURCE("BTimeSource::PublishTime timesource %" B_PRId32
    319387        ", perf %16" B_PRId64 ", real %16" B_PRId64 ", drift %2.2f\n", ID(),
    BTimeSource::PublishTime(bigtime_t performance_time,  
    332400    fBuf->perftime[index] = performance_time;
    333401    fBuf->drift[index] = drift;
    334402    atomic_add(&fBuf->readindex, 1);
    335 
    336 //  printf("BTimeSource::PublishTime timesource %ld, write index %ld, perf %16Ld, real %16Ld, drift %2.2f\n", ID(), index, performance_time, real_time, drift);
    337403}
    338404
    339405
    340406void
    341407BTimeSource::BroadcastTimeWarp(bigtime_t at_real_time,
    342                                bigtime_t new_performance_time)
     408    bigtime_t new_performance_time)
    343409{
    344410    CALLED();
    345411    ASSERT(fSlaveNodes != NULL);
    BTimeSource::BroadcastTimeWarp(bigtime_t at_real_time,  
    350416        ", new_performance_time %" B_PRId64 "\n", at_real_time,
    351417        new_performance_time);
    352418
    353     BAutolock lock(fSlaveNodes->locker);
     419    BAutolock lock(fSlaveNodes);
    354420
    355     for (int i = 0, n = 0; i < SLAVE_NODES_COUNT && n != fSlaveNodes->count; i++) {
    356         if (fSlaveNodes->node_id[i] != 0) {
    357             node_time_warp_command cmd;
    358             cmd.at_real_time = at_real_time;
    359             cmd.to_performance_time = new_performance_time;
    360             SendToPort(fSlaveNodes->node_port[i], NODE_TIME_WARP, &cmd, sizeof(cmd));
    361             n++;
    362         }
     421    for (int i = 0; i < fSlaveNodes->CountSlaves(); i++) {
     422        node_time_warp_command cmd;
     423        cmd.at_real_time = at_real_time;
     424        cmd.to_performance_time = new_performance_time;
     425        SendToPort(fSlaveNodes->PortAt(i), NODE_TIME_WARP,
     426            &cmd, sizeof(cmd));
    363427    }
    364428}
    365429
    BTimeSource::SendRunMode(run_mode mode)  
    372436
    373437    // send the run mode change to all slaved nodes
    374438
    375     BAutolock lock(fSlaveNodes->locker);
     439    BAutolock lock(fSlaveNodes);
    376440
    377     for (int i = 0, n = 0; i < SLAVE_NODES_COUNT && n != fSlaveNodes->count; i++) {
    378         if (fSlaveNodes->node_id[i] != 0) {
    379             node_set_run_mode_command cmd;
    380             cmd.mode = mode;
    381             SendToPort(fSlaveNodes->node_port[i], NODE_SET_RUN_MODE, &cmd, sizeof(cmd));
    382             n++;
    383         }
     441    for (int i = 0; i < fSlaveNodes->CountSlaves(); i++) {
     442        node_set_run_mode_command cmd;
     443        cmd.mode = mode;
     444        SendToPort(fSlaveNodes->PortAt(i), NODE_SET_RUN_MODE,
     445            &cmd, sizeof(cmd));
    384446    }
    385447}
    386448
    status_t BTimeSource::_Reserved_TimeSource_4(void *) { return B_ERROR; }  
    410472status_t BTimeSource::_Reserved_TimeSource_5(void *) { return B_ERROR; }
    411473
    412474/* explicit */
    413 BTimeSource::BTimeSource(media_node_id id) :
     475BTimeSource::BTimeSource(media_node_id id)
     476    :
    414477    BMediaNode("This one is never called"),
    415478    fStarted(false),
    416479    fArea(-1),
    BTimeSource::BTimeSource(media_node_id id) :  
    421484    CALLED();
    422485    AddNodeKind(B_TIME_SOURCE);
    423486    ASSERT(id > 0);
    424 //  printf("###### explicit BTimeSource::BTimeSource() id %ld, name %s\n", id, Name());
    425487
    426     // This constructor is only called by the derived BPrivate::media::TimeSourceObject objects
    427     // We create a clone of the communication area
     488    // This constructor is only called by the derived
     489    // BPrivate::media::TimeSourceObject objects
     490    // We create a clone of the communication area.
    428491    char name[32];
    429492    area_id area;
    430493    sprintf(name, "__timesource_buf_%" B_PRId32, id);
    BTimeSource::BTimeSource(media_node_id id) :  
    435498        return;
    436499    }
    437500    sprintf(name, "__cloned_timesource_buf_%" B_PRId32, id);
    438     fArea = clone_area(name, reinterpret_cast<void **>(const_cast<BPrivate::media::TimeSourceTransmit **>(&fBuf)), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, area);
     501
     502    void** buf = reinterpret_cast<void**>
     503        (const_cast<BPrivate::media::TimeSourceTransmit**>(&fBuf));
     504
     505    fArea = clone_area(name, buf, B_ANY_ADDRESS,
     506        B_READ_AREA | B_WRITE_AREA, area);
     507
    439508    if (fArea <= 0) {
    440509        ERROR("BTimeSource::BTimeSource couldn't clone area, node %" B_PRId32
    441510            "\n", id);
    void  
    448517BTimeSource::FinishCreate()
    449518{
    450519    CALLED();
    451     //printf("BTimeSource::FinishCreate(), id %ld\n", ID());
    452520
    453521    char name[32];
    454522    sprintf(name, "__timesource_buf_%" B_PRId32, ID());
    455     fArea = create_area(name, reinterpret_cast<void **>(const_cast<BPrivate::media::TimeSourceTransmit **>(&fBuf)), B_ANY_ADDRESS, TS_AREA_SIZE, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
     523
     524    void** buf = reinterpret_cast<void**>
     525        (const_cast<BPrivate::media::TimeSourceTransmit**>(&fBuf));
     526
     527    fArea = create_area(name, buf, B_ANY_ADDRESS, TS_AREA_SIZE,
     528        B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
     529
    456530    if (fArea <= 0) {
    457531        ERROR("BTimeSource::BTimeSource couldn't create area, node %" B_PRId32
    458532            "\n", ID());
    BTimeSource::FinishCreate()  
    469543
    470544
    471545status_t
    472 BTimeSource::RemoveMe(BMediaNode *node)
     546BTimeSource::RemoveMe(BMediaNode* node)
    473547{
    474548    CALLED();
    475549    if (fKinds & NODE_KIND_SHADOW_TIMESOURCE) {
    476550        timesource_remove_slave_node_command cmd;
    477551        cmd.node = node->Node();
    478         SendToPort(fControlPort, TIMESOURCE_REMOVE_SLAVE_NODE, &cmd, sizeof(cmd));
     552        SendToPort(fControlPort, TIMESOURCE_REMOVE_SLAVE_NODE,
     553            &cmd, sizeof(cmd));
    479554    } else {
    480555        DirectRemoveMe(node->Node());
    481556    }
    BTimeSource::RemoveMe(BMediaNode *node)  
    484559
    485560
    486561status_t
    487 BTimeSource::AddMe(BMediaNode *node)
     562BTimeSource::AddMe(BMediaNode* node)
    488563{
    489564    CALLED();
    490565    if (fKinds & NODE_KIND_SHADOW_TIMESOURCE) {
    BTimeSource::AddMe(BMediaNode *node)  
    499574
    500575
    501576void
    502 BTimeSource::DirectAddMe(const media_node &node)
     577BTimeSource::DirectAddMe(const media_node& node)
    503578{
    504579    // XXX this code has race conditions and is pretty dumb, and it
    505580    // XXX won't detect nodes that crash and don't remove themself.
    506581
    507582    CALLED();
    508583    ASSERT(fSlaveNodes != NULL);
    509     BAutolock lock(fSlaveNodes->locker);
     584    BAutolock lock(fSlaveNodes);
    510585
    511     if (fSlaveNodes->count == SLAVE_NODES_COUNT) {
     586    if (fSlaveNodes->CountSlaves() == MAX_SLAVE_NODES) {
    512587        ERROR("BTimeSource::DirectAddMe out of slave node slots\n");
    513588        return;
    514589    }
    BTimeSource::DirectAddMe(const media_node &node)  
    516591        ERROR("BTimeSource::DirectAddMe should not add itself to slave nodes\n");
    517592        return;
    518593    }
    519     for (int i = 0; i < SLAVE_NODES_COUNT; i++) {
    520         if (fSlaveNodes->node_id[i] == 0) {
    521             fSlaveNodes->node_id[i] = node.node;
    522             fSlaveNodes->node_port[i] = node.port;
    523             fSlaveNodes->count += 1;
    524             if (fSlaveNodes->count == 1) {
    525                 // start the time source
    526                 time_source_op_info msg;
    527                 msg.op = B_TIMESOURCE_START;
    528                 msg.real_time = RealTime();
    529                 TRACE_TIMESOURCE("starting time source %" B_PRId32 "\n", ID());
    530                 write_port(fControlPort, TIMESOURCE_OP, &msg, sizeof(msg));
    531             }
    532             return;
    533         }
     594
     595    if (fSlaveNodes->InsertSlave(node) != true)
     596        ERROR("BTimeSource::DirectAddMe failed\n");
     597
     598    if (fSlaveNodes->CountSlaves() == 1) {
     599        // start the time source
     600        time_source_op_info msg;
     601        msg.op = B_TIMESOURCE_START;
     602        msg.real_time = RealTime();
     603
     604        TRACE_TIMESOURCE("starting time source %" B_PRId32 "\n", ID());
     605
     606        write_port(fControlPort, TIMESOURCE_OP, &msg, sizeof(msg));
    534607    }
    535     ERROR("BTimeSource::DirectAddMe failed\n");
    536608}
    537609
    538610void
    539 BTimeSource::DirectRemoveMe(const media_node &node)
     611BTimeSource::DirectRemoveMe(const media_node& node)
    540612{
    541613    // XXX this code has race conditions and is pretty dumb, and it
    542614    // XXX won't detect nodes that crash and don't remove themself.
    543615
    544616    CALLED();
    545617    ASSERT(fSlaveNodes != NULL);
    546     BAutolock lock(fSlaveNodes->locker);
     618    BAutolock lock(fSlaveNodes);
    547619
    548     if (fSlaveNodes->count == 0) {
     620    if (fSlaveNodes->CountSlaves() == 0) {
    549621        ERROR("BTimeSource::DirectRemoveMe no slots used\n");
    550622        return;
    551623    }
    552     for (int i = 0; i < SLAVE_NODES_COUNT; i++) {
    553         if (fSlaveNodes->node_id[i] == node.node && fSlaveNodes->node_port[i] == node.port) {
    554             fSlaveNodes->node_id[i] = 0;
    555             fSlaveNodes->node_port[i] = 0;
    556             fSlaveNodes->count -= 1;
    557             if (fSlaveNodes->count == 0) {
    558                 // stop the time source
    559                 time_source_op_info msg;
    560                 msg.op = B_TIMESOURCE_STOP_IMMEDIATELY;
    561                 msg.real_time = RealTime();
    562                 TRACE_TIMESOURCE("stopping time source %" B_PRId32 "\n", ID());
    563                 write_port(fControlPort, TIMESOURCE_OP, &msg, sizeof(msg));
    564             }
    565             return;
    566         }
     624
     625    if (fSlaveNodes->RemoveSlave(node) != true)
     626        ERROR("BTimeSource::DirectRemoveMe failed\n");
     627
     628    if (fSlaveNodes->CountSlaves() == 0) {
     629        // stop the time source
     630        time_source_op_info msg;
     631        msg.op = B_TIMESOURCE_STOP_IMMEDIATELY;
     632        msg.real_time = RealTime();
     633
     634        TRACE_TIMESOURCE("stopping time source %" B_PRId32 "\n", ID());
     635
     636        write_port(fControlPort, TIMESOURCE_OP, &msg, sizeof(msg));
    567637    }
    568     ERROR("BTimeSource::DirectRemoveMe failed\n");
    569638}
    570639
    571640void
    BTimeSource::DirectStart(bigtime_t at)  
    580649
    581650
    582651void
    583 BTimeSource::DirectStop(bigtime_t at,
    584                         bool immediate)
     652BTimeSource::DirectStop(bigtime_t at, bool immediate)
    585653{
    586654    CALLED();
    587655    if (fBuf)
    BTimeSource::DirectStop(bigtime_t at,  
    592660
    593661
    594662void
    595 BTimeSource::DirectSeek(bigtime_t to,
    596                         bigtime_t at)
     663BTimeSource::DirectSeek(bigtime_t to, bigtime_t at)
    597664{
    598665    UNIMPLEMENTED();
    599666}